Java 多线程—下篇

线程的生命周期

线程的状态:

获取线程的状态的方法:public State getState()

线程状态类型:

NEW // 新建

RUNNABLE // 可运行的

BLOCKED // 阻塞

WAITING // 等待

TIMED_WAITING // 定时等待

TERMINATED // 终于

线程生命周期:
在这里插入图片描述
在这里插入图片描述


线程控制方法:

  • 设置线程的优先级:setPriority(int)
  • 设置守护线程:setDaemon(boolean)
  • 暂停线程执行指定时间:sleep(long)
  • 联结线程:join( )中断线程:interrupt( )
  • 线程礼让:yield( )
  • 已经弃用的线程控制方法:suspend( )、resume( )、stop( )

Thread类的setPriority(int)方法

括号里的数值参数为 1-10 的整数值,值越大优先级越高

若参数不是 1-10 的整数值,会发生异常

我们可以用代码来看一下

/*
	需求:
		创建两个线程,分别设置为最小优先级和最大优先级,启动两个线程,分别输出0~99,观察输出结果。
	操作步骤:
		定义类,实现Runnable接口,run()方法中循环打印。
		定义测试类,main方法中创建线程,设置线程优先级并启动线程。
*/
public class RunnableImpl implements Runnable {
        @Override
        public void run() {
                for(int i=1; i<100; i++)
                {
                       System.out.println(Thread.currentThread().getName() + ", " + i);
                }
        }
}

//分别创建名为MinPriority和MaxPriority的线程,设置优先级分别为1和10
public static void main(String[] args) {
        Thread td1 = new Thread(new RunnableImpl(),“ MinPriority”);
        td1.setPriority(1);
        Thread td2 = new Thread(new RunnableImpl() , “ MaxPriority”);
        td2.setPriority(10);
        td1.start();
        td2.start();
}

Thread类的setDaemon(boolean)方法

设置线程是否为守护线程

布尔类型的参数为true时,代表设置为守护线程

为其它线程提供服务、随着用户线程终止而终止的线程

废话就不多说了,上代码

/*
	需求:
		创建两个线程,分别输出0~99,将其中一个设置为守护线程,启动两个线程,观察输出结果。
	操作步骤:
		定义类,实现Runnable接口,run()方法中循环打印。
		定义测试类,main方法中创建线程,设置守护线程并启动线程。
*/
public class RunnableImpl implements Runnable {
        @Override
        public void run() {
                for(int i=1; i<100; i++)
                {
                       System.out.println(Thread.currentThread().getName() + ", " + i);
                }
        }
}

//分别创建名为Daemon和User的线程,将名为Daemon的线程设置为守护线程
public static void main(String[] args) {
        Thread td1 = new Thread( new RunnableImpl()"Daemon";
        td1.setPriority(1);
        td1.setDaemon(true);
        Thread td2 = new Thread( new RunnableImpl() ,"User");
        td2.setPriority(10);
        td1.start();
        td2.start();
}

Thread类的sleep()方法

当前线程暂停执行参数指定的时间(单位:毫秒)

1秒=1000毫秒

正确用法:Thread.sleep(1000);

使用该方法需要处理该异常 : InterruptedException

public class MyThread extends Thread{
        @Override
        public void run() {
                Thread td = currentThread();
                for(int i=1; i<10; i++)
                {                      
                      System.out.println("MyThread" + td.getName() 
                             + ", " + System.currentTimeMillis() + td.getState() + ", "+ i);
                      try {
                            Thread.sleep(1000);
                      } catch (InterruptedException e) {
                            e.printStackTrace();
                      }
                }
        }    
}

public static void main(String[] args) {
        Thread td1 = new MyThread();
        td1.start();
         for(int i=1; i<10; i++)
         {
               System.out.println("td1 state is :" + td1.getState() + ", " + System.currentTimeMillis());
        }
}

Thread类的join()方法

将线程加入到当前线程当,前线程进入等待状态,等待加入的线程终止或指定时长结束

public class MyThread extends Thread{
        @Override
        public void run() {
                Thread td = currentThread();
                for(int i=1; i<10; i++)
                {
                     System.out.println("MyThread" + td.getName() + ", " + td.getState() + ", "+ i);
                }
        }    
}

public static void main(String[] args) throws InterruptedException{
        Thread td1 = new MyThread();
        td1.start();
        td1.join();
         for(int i=1; i<10; i++)
         {
               System.out.println("td1 state is :" + td1.getState() + ", " + System.currentTimeMillis());
        }
}

Thread类的yield()方法

当前线程让出执行权,以允许具有相同优先级的其它线程获得运行机会

public class YieldThread extends Thread {
       …… //构造方法省略
       @Override
       public void run() {
              for(int i=1; i<100; i++){
        	     Thread.yield();
        	     System.out.println("Thread name: " + getName() + ", " + getPriority() + "," + i);
              }
       }
}

public class YieldTest {
       public static void main(String[] args) {
              Thread td1 = new YieldThread("YieldThread");
              td1.start();
              for(int i=1; i<1000; i++){
        	     System.out.println("Thread name: " + Thread.currentThread().getName() + ", "  + Thread.currentThread().getPriority() + "," + i);
              }
       }
}

Thread类的interrupt() 方法

向线程发出中断请求

注意:

​ 该方法仅设置线程的中断状态,并不中断线程的运行!

​ 线程通过判断中断状态标识对中断请求进行处理。

​ 中断阻塞状态的线程会触发该线程的InterruptedException

//判断当前线程是否被中断的方法
public static boolean interrupted(){
    return currentThread().isInterrupted(true);
}
//静态方法调用静态方法,获取当前线程
private native boolean isInterrupted(boolean ClearInterrupted);
//native方法,参数表示是否清除中断状态标志
//true表示查询完就清除中断标志

需求:

创建长工作线程,循环1000次,输出线程名和当前循环次数。主线程中启动线程后请求中断该线程。(1)长工作线程不处理中断;

(2)长工作线程处理中断,在收到中断请求后跳出循环,结束;

(3)长工作线程在休眠时的中断处理。

//线程不处理中断代码示例
public class LongWork implements Runnable {
        @Override
        public void run() {
               String tdName = Thread.currentThread().getName();
                for(int i=1; i<1000; i++){
	        System.out.println(tdName + ", " + i);
        	   }
         }
}

public static void main(String[] args) throws InterruptedException {
        LongWork lw = new LongWork();
        Thread lwTd = new Thread(lw, "LongWork");
        lwTd.start();
        System.out.println(" Long Work Thread: “ + ", " + lwTd.getState());
        lwTd.interrupt();
        System.out.println(" After interrupt: Long Work Thread: “  + ", " + lwTd.getState());
        Thread.sleep(100);
        System.out.println(" After 100ms, Long Work Thread: "  + ", " + lwTd.getState());
}
//线程处理中断代码示例
public class LongWork implements Runnable {
        @Override
        public void run() {
               String tdName = Thread.currentThread().getName();
                for(int i=1; i<1000; i++){
        	        if(Thread.interrupted()){
        		System.out.println(tdName + " is interrupted. " );
        		break;
        	     	}
        	        System.out.println(tdName + ", " + i);
        	   }
         }
}

public static void main(String[] args) throws InterruptedException {
        LongWork lw = new LongWork();
        Thread lwTd = new Thread(lw, "LongWork");
        lwTd.start();
        System.out.println(" Long Work Thread: “ + ", " + lwTd.getState());
        lwTd.interrupt();
        System.out.println(" After interrupt: Long Work Thread: “  + ", " + lwTd.getState());
        Thread.sleep(100);
        System.out.println(" After 100ms, Long Work Thread: "  + ", " + lwTd.getState());
}
//线程休眠时被中断代码示例
public class LongWork implements Runnable {
        @Override
        public void run() {
               String tdName = Thread.currentThread().getName();
                for(int i=1; i<1000; i++){
	        System.out.println(tdName + ", " + i);
                       try {
                             Thread.sleep(1000);
                       } catch (InterruptedException e) {
                             System.out.println("Thread name: " + td.getName()  + "InterruptedException occured!" );
                             e.printStackTrace();
                       } 
			  }      
        }     
}

public static void main(String[] args) throws InterruptedException {
        LongWork lw = new LongWork();
        Thread lwTd = new Thread(lw, "LongWork");
        lwTd.start();
        Thread.sleep(100);
        System.out.println(" Long Work Thread: “ + ", " + lwTd.getState());
        lwTd.interrupt();
        System.out.println(" After interrupt: Long Work Thread: “  + ", " + lwTd.getState());
        Thread.sleep(100);
        System.out.println(" After 100ms, Long Work Thread: "  + ", " + lwTd.getState());
}

###再次细聊 ‘锁‘

  • synchronized 隐式同步锁
  • Lock 同步锁

####synchronized

隐式同步锁(synchronized):是指Java中使用synchronized修饰方法和代码块实现线程互斥的机制

synchronized可以修饰除构造方法外的所有方法

【其它修饰符】 synchronized 返回值类型 方法名(参数列表)

示例:

//StringBuffer中的length()方法     同步方法
public synchronized int length(){
    return count;
}
//synchronized修饰非静态方法时:
	//对于同一个对象,同一时刻只能有一个线程执行该方法
//synchronized修饰静态方法时:
	//同一时刻只能有一个线程执行该方法

//常用的System.out.println(String)方法    
public void println(String){
    synchronized(this){		//同步代码块    this为同步监视器
        print(x);
        newLine();
    }
}
//同步代码块必须指定同步监视器(提供内置锁的对象)
//synchronized(obj){
    //同一时刻只允许一个线程执行的代码
//}

同步方法中同步监视器的定义:

  • synchronized修饰非静态方法时:默认使用当前对象this作为同步监视器
  • synchronized修饰静态方法时:默认使用类的Class对象作为同步监视器

####Lock

显式同步锁(Lock):是指Java中使用Lock接口实现类对象作为互斥信号的同步机制

Lock接口声明的方法

public interface Lock {
       void lock();     //获取锁,当前不可用则阻塞,直到获取为止
       void lockInterruptibly() throws InterruptedException;
       boolean tryLock();     //获取锁,当前不可用则返回false
       boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
       void unlock();    //释放锁
       Condition newCondition();
}

ReentrantLock是Java提供的、允许一个线程多次获取同一个锁对象的Lock接口实现类

####读写锁与死锁

ReadWriteLock接口声明的方法

public interface ReadWriteLock {
       Lock readLock();   //返回用于控制读权限的锁对象
       Lock writeLock();  //返回用于控制写权限的锁对象
}

ReentrantReadWriteLock是Java提供的、允许一个线程多次获取同一个锁对象的ReadWriteLock接口实现类

死锁是两个或以上的执行单元由于资源竞争或互相等待而形成僵持的状态

  • 两个或以上的执行单元
  • 由于资源竞争或互相等待而僵持

死锁发生的条件:

  • 资源的互斥使用请求和保持:
  • 已经得到某些资源后还可以申请其它新资源
  • 不可剥夺:已经分配的资源在占有者没有释放之前不允许被剥夺
  • 环路等待

死锁的预防

  • 资源改造
  • 无法获取新资源时释放已有资源
  • 资源预先分配策略
  • 资源有序分配策略

死锁的避免

  • 分配资源时动态检查

死锁的解除

  • 外力干预

#####两种锁的比较

01 02 03 04
synchronized 作用于方法或代码块 任何对象都可以作为同步监视器 自动获取和释放 可能产生死锁
Lock 可以灵活地对Lock锁进行操作 Lock接口实现类对象 显式获取和释放 可能产生死锁

线程通信

线程通信是同一进程中的线程间共享数据和信号传递的机制

  • 同一进程中的线程间
  • 以数据共享和信号传递为目的

传统线程通信

synchronized中使用同步监视器对象的以下Object类方法进行通信:

  • wait():当前线程释放监视器锁,进入等待状态,直至其它线程调用该同步监视器的notify()方法或notifyAll()方法
  • wait(long):当前线程等待,直到参数指定的时间结束
  • notify():唤醒一个等待该同步监视器的线程,有多个线程等待时,任意选择一个
  • norifyAll():唤醒所有等待该同步监视器的线程

Lock的Condition通信

猜你喜欢

转载自blog.csdn.net/weixin_43650254/article/details/85091069