自定义线程
实现方式
- 继承Thread类
- 实现Runnable 接口
继承Thread 类
- 继承Thread后,要重写run 方法
- public void run 方法体 为该线程要执行的任务
- 启动线程的方法为start() ,不是调用run()
- 调用run方法不能开启新的线程,只是普通的函数调用
- 线程的生命周期类只能被启动一次
public class xiancheng2 {
public static void main(String[] args) {
//创建对象
Myrun run1 = new Myrun();
//创建线程对象
Thread runTd = new Thread( run1 );
// 开启线程
runTd.start();
run1.say();
}
}
class Myrun extends Thread{
@Override
public void run() {
System.out.println("新的线程");
}
public void say() {
System.out.println( "美好的一天" );
}
}
常用API
String getName() | 返回该线程的名称。 |
long getId() | 返回该线程的标识符。 |
int getPriority() | 返回线程的优先级。 |
Thread.State getState() | 返回该线程的状态。 |
join() | 等待该线程终止。 |
join( long millis ) | 等待该线程终止的时间最长为 millis 毫秒。 |
static void sleep(long millis ) | 在指定的毫秒数内让当前正在执行的线程休眠(暂停执行)。 |
void start() | |
void interrupt() | 中断线程。 |
static boolean interrupted() | 测试当前线程是否已经中断。 |
boolean isDaemon() | 测试该线程是否为守护线程。 |
实现Runnable 接口
方法与继承Tread 类似即:
- 继承Runnable 接口,实现run 方法
- 创建线程对象 , 开启线程
差异
- 通过接口的方式,更加灵活(Java是单继承)
- 继承的方式更加简单。(使用较少)
线程状态
- 一个线程一般要经历5个状态
- 新建状态
- 准备状态
- 运行状态
- 等待/阻塞状态
- 睡眠 : 调用sleep()
- 阻塞 :
- 挂起 : 调用suspend 挂起,resume()解除挂起 ( 不建议使用)
- 等待 : 调用 wait()
- 死亡状态
线程的使用
睡眠
调用sleep方法可以让线程睡眠指定的时间后再苏醒进入准备状态,
-
public static void sleep( long millis) throw InterruptedException
-
public static void sleep( long millis , int nanos) throw InterruptedException
-
public class xiancheng2 {
public static void main(String[] args) throws InterruptedException{
//创建对象
Myrun run1 = new Myrun();
//创建线程对象
Thread runTd = new Thread( run1 );
Thread runTd2 = new Thread( run1 );
// 开启线程
runTd.start();
//使主线程睡眠100ms
Thread.sleep(100);
System.out.println( "美好的一天" );
}
}
class Myrun implements Runnable{
@Override
public void run() {
System.out.println("新的线程");
try {
// 使该线程睡眠100ms
Thread.sleep(100);
} catch (Exception e) {
// TODO: handle exception
}
}
}
线程的优先级
- Java中线程的优先级用1~10之间的整数表示。值越大,优先级越高。默认为5
不适合对线程进行细节调节
主线程的优先级默认为5。子线程优先级初始值与父线程相同。
改变优先级:(不能精确)
-
public final void setPriority( int newPriority )
-
public class xiancheng2 {
public static void main(String[] args) {
//创建对象
Myrun run1 = new Myrun(1);
Myrun run2 = new Myrun(2);
//创建线程对象
Thread runTd1 = new Thread( run1 );
Thread runTd2 = new Thread( run2 );
//设置优先级
runTd2.setPriority( Thread.MIN_PRIORITY );//最高的优先级
runTd1.setPriority( Thread.MAX_PRIORITY );//最低的优先级
//开启线程
runTd2.start();
runTd1.start();
}
}
class Myrun implements Runnable{
private int id ;
public Myrun(int id) {
this.id = id;
}
@Override
public void run() {
System.out.println("新的线程"+ this.id);
}
}
线程的让步
- 分类
- 线程只是让出当前的CPU资源,具体将CPU让给谁不能确定 (无保障)
- 线程将给指定的线程让步,指定的线程没有完成,其绝不恢复执行 (线程合并--有保障)
yield方法
使当前正在运行的线程让出CPU,回到准备状态。(无保障)
-
pubic static void yield()
-
join方法
调用join方法的线程将执行完,后再恢复其他线程执行
-
public final void join( ) throw InterruptedException
-
public final void join( long millis) throw InterruptedException
-
public final void join( long millis ,int nanos ) throw InterruptedException
-
public class xiancheng2 {
public static void main(String[] args) throws InterruptedException{
Thread run1 = new Myrun("先");
Thread run2 = new Myrun("后");
run2.start();
run2.join(); //run2线程将执行完后,在恢复其他线程。
run1.start();
for (int i = 0; i < 50; i++) {
System.out.print(6);
}
}
}
class Myrun extends Thread{
private String id ;
public Myrun(String id) {
this.id = id;
}
@Override
public void run() {
try {
} catch (Exception e) {
// TODO: handle exception
}
for(int i=100 ;i>0;i--) {
System.out.print(this.id);
}
}
}
注意(有参)
如果A线程中掉用B线程的join(10),则表示A线程会等待B线程执行10毫秒,10毫秒过后,A、B线程并行执行。
需要注意的是,jdk规定,join(0)的意思不是A线程等待B线程0秒,而是A线程等待B线程无限时间,直到B线程执行完毕,即join(0)等价于join()。
摘自:https://www.cnblogs.com/ldq2016/p/9045551.html
线程守护
- 在后台运行的线程(内存管理,线程调度...) 称之为守护线程
开发守护线程
-
public final void setDaemon( boolean on ) // on表示是否设置为守护线程(fal se:普通线程)
- java中 : 但前台线程(普通线程)都运行结束后,程序退出
- 与回台程序是否运行完无关。
- java中 : 但前台线程(普通线程)都运行结束后,程序退出
-
同步线程
同步方法
同步方法是指用synchronized修饰的方法
-
synchronized <返回类型> 方法名 ([参数列表])[throw 异常]{ 返回类型>
}
- 静态的同步方法的锁对象为 : 当前的class的对象
- 非静态的同步方法的锁对象为 :this
- 当线程获得锁锁后进入睡眠或让步,将带着锁一起睡眠,让步。
- 同步方法退出后,锁将被释放,等待其他的线程可以获取锁。
- 同步将会降低多线程的并发性。
-
public class tridet {
public static void main(String[] args) {
Ticket tck = new Ticket();
Thread t2 = new Thread(tck,"window1");
Thread t1 = new Thread(tck,"window2");
Thread t3 = new Thread(tck,"window3");
System.out.println( "tck: " + tck );
t1.start();
t2.start();
t3.start();
}
}
class Ticket implements Runnable{
private int TicketNum = 100;
public void run() {
while( this.TicketNum>0 ) {
this.buy();
}
}
public synchronized void buy() {
System.out.println( this ); // this ==> tck(锁对象)
if(this.TicketNum-->0)
System.out.println(Thread.currentThread().getName() + "买出一张票,还剩:" + this.TicketNum );
}
}
同步调度方法
final void wait() | 使某个线程进入等待状态。直到别的线程调用notify或notifyAll方法将其唤醒 |
final void wait(long timeout) | timeout 毫秒数,使某个线程进入等待状态,直至达到等待时间,或将其唤醒为止。 |
final void notify() | 唤醒等待池中的某一个线程(没有保障,不能确定唤醒哪一个线程) |
final void notifyAll() | 唤醒等待池中的所有线程 |
同步语句块
synchronized (锁对象){ }
- 锁对象要唯一
- 锁对象就如同一个保管钥匙的人,要使保证同步那么就要保证只有当一个线程执行完了同步语句块后(归还钥匙)其他的线程才能进入同步语句块,所有保管钥匙的人要唯一(钥匙只有一把)。
public class tridet {
public static void main(String[] args) {
// TODO Auto-generated method stub
Thread t2 = new Ticket("window2");
Thread t1 = new Ticket("window1");
Thread t3 = new Ticket("window3");
t1.start();
t2.start();
t3.start();
}
}
class Ticket extends Thread{
private static int TicketNum = 10;
private static Object look = new Object(); // 锁对象(唯一)
public void run() {
while( this.TicketNum > 0 ) {
synchronized (look) {
if(this.TicketNum--<=0) break;
System.out.println(getName() + "买出一张票,还剩:" + this.TicketNum );
}
}
}
public Ticket(String name) {
super(name);
}
}
public class tridet {
public static void main(String[] args) {
Ticket tck = new Ticket();
Thread t2 = new Thread(tck,"window1");
Thread t1 = new Thread(tck,"window2");
Thread t3 = new Thread(tck,"window3");
t1.start();
t2.start();
t3.start();
}
}
class Ticket implements Runnable{
private int TicketNum = 100;
public void run() {
while( this.TicketNum > 0 ) {
synchronized (this) { //锁对象为this , 即:tck对象(唯一)
if(this.TicketNum--<=0) break;
System.out.println(Thread.currentThread().getName() + "买出一张票,还剩:" + this.TicketNum );
}
}
}
}
死锁
- 相互等待对方释放资源的对象的 锁。
public class shisuo {
public static void main(String[] args) {
// TODO Auto-generated method stub
Object oj1 = new Object();
Object oj2 = new Object();
boy b1 = new boy( oj1 , oj2 );
girl g1 = new girl( oj1 , oj2 );
Thread thread1 = new Thread(b1,"boy");
Thread thread2 = new Thread(g1,"boy");
thread1.start();
thread2.start();
}
}
class boy implements Runnable {
private Object look1, look2;
public boy(Object look1, Object look2) {
super();
this.look1 = look1;
this.look2 = look2;
}
public void run() {
synchronized (look1) {
System.out.println("body");
synchronized (look2) {
System.out.println("body2");
}
}
}
}
class girl implements Runnable {
private Object look1, look2;
public girl(Object look1, Object look2) {
super();
this.look1 = look1;
this.look2 = look2;
}
public void run() {
synchronized (look2) {
System.out.println("girl");
synchronized (look1) {
System.out.println("girl2");
}
}
}
}
volatile 关键字
作用:被其修饰的成员变量不允许一个线程对其操作过程中,其他线程插入操作。
- 该关键字只允许修饰成员变量 , 不能修饰局部变量。
- 局部变量不可能同时被两个线程