多线程常用操作方法

多线程常用操作方法

  • 线程命名和取得
  • 线程休眠
  • 线程中断
  • 强制线程执行
  • 线程礼让
  • 线程优先级
  • 线程的同步
    • 引出:3个线程卖3张票
    • 同步代码块
    • 同步方法
  • 线程死锁
  • 综合案例
  • Object线程等待和唤醒
  • 优雅地停止线程
  • 守护线程
  • volatile关键字

线程命名和取得

三个方法:构造方法设置,setName方法,getName方法
示例:

 static class Mythread implements Runnable{
  @Override
  public void run() {
   // TODO Auto-generated method stub 
   //获取当前线程名称
   System.out.println(Thread.currentThread().getName());
  }  
 }
 public static void main(String[] args){
  Mythread mt = new Mythread();
  new Thread(mt,"线程A").start();//手动命名  --线程A
  new Thread(mt).start();//自动命名  --Thread-0
  mt.run();//输出主线程你名称 (从输出结果也能看出先运行的是主线程)--main
 }

线程休眠

示例:

 public static void main(String[] args){
  Runnable run = () -> {
   for(int x = 0; x < 10 ; x++) {
    System.out.println(Thread.currentThread().getName() + ",x="+x);
    try {
     Thread.sleep(1000);//暂缓1秒执行
    } catch (InterruptedException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }
   }
  };
  for(int num = 0 ;num < 5 ;num ++) {
   new Thread(run,"线程对象" + num).start();
  }
 }

线程中断

方法 描述
public boolean isInterrupted() 判断线程是否被中断
public void interrupt() 中断线程执行
 public static void main(String[] args) throws Exception{
  Thread thread = new Thread(() ->  {
   System.out.println("[BEFORE]准备睡觉10s,不要打扰我");
   try {
    Thread.sleep(10000);
    System.out.println("[FINISH]睡醒了,准备工作和学习");
   } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
  });
  thread.start();
  Thread.sleep(1000);//保证子线程先运行1s
  if(!thread.isInterrupted()) {
   System.out.println("[INTERRUPT]敲锣打鼓惊天洗地地经过你睡觉的地方");
   thread.interrupt();
  }
 }

强制线程执行

public final void join() throws InterruptedException

 public static void main(String[] args) throws Exception{
  Thread mainThread = Thread.currentThread();//获得主线程
  Thread thread = new Thread(() -> {
   for(int i =0 ; i< 100 ; i++) {
    if( i == 3) {
     try {
      mainThread.join();//强制执行线程任务
     } catch (InterruptedException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
     }
    }
    try {
     Thread.sleep(100);
    } catch (InterruptedException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }
    System.out.println(Thread.currentThread().getName()+"执行x:"+i);
   }
  },"玩耍的线程");
  thread.start();
  for(int x =0 ; x< 100 ; x++) {
   thread.sleep(100);
   System.out.println("[霸道的main线程] number = " +x);
  }
 }

在 i<3时,两个线程会交替执行,而当i=3时,会在主线程执行完毕后再执行子线程

线程礼让

public static void yield()

 public static void main(String[] args) throws Exception{
  Thread thread = new Thread(() -> 
  {
   for(int x = 0 ;x < 100 ; x++) {
    if(x % 3 == 0 ) {
     Thread.yield();//线程礼让
     System.out.println("[YIELD]线程礼让"+Thread.currentThread().getName());
    }
    try {
     Thread.sleep(100);
    } catch (InterruptedException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }
    System.out.println(Thread.currentThread().getName()+"执行x:"+x);
   }
  },"玩耍的线程");
  thread.start();
  for(int x = 0 ;x < 100; x++ ) {
   Thread.sleep(100);
   System.out.println("[霸道的main线程] number:"+x);
  }
 }

线程优先级

方法 描述
public static final int MAX_PRIORITY 最高优先级,数值为10
public static final int NORM_PRIORITY 中等优先级,数值为5
public static final int MIN_PRIORITY 最低优先级,数值为1
public final void setPriority(int NewPriority) 设置线程优先级
public final int getPriority 取得线程优先级

主方法的优先级为5

 public static void main(String[] args) throws Exception{
  Runnable run = () -> {
   for(int x = 0 ; x < 10 ; x++) {
    try {
     Thread.sleep(1000);
    } catch (InterruptedException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }
    System.out.println(Thread.currentThread().getName() + "执行。");
   }
  };
  Thread threadA = new Thread(run,"线程A");
  Thread threadB = new Thread(run,"线程B");
  Thread threadC = new Thread(run,"线程C");
  //设置优先级,理论上优先级越高越有可能抢占资源
  threadA.setPriority(Thread.MIN_PRIORITY);
  threadB.setPriority(Thread.NORM_PRIORITY);
  threadC.setPriority(Thread.MAX_PRIORITY);
  threadA.start();
  threadB.start();
  threadC.start();
 }

线程的同步

引出:3个线程卖3张票

 static class Mythread implements Runnable{
 private int ticket = 3;
  @Override
  public void run() {
   // TODO Auto-generated method stub
   while(true) {//持续卖票
    if(this.ticket > 0) {
     try {
      Thread.sleep(100);
     } catch (InterruptedException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
     }
     System.out.println("卖票 ticket:"+this.ticket --);
    }else {
     System.out.println("****票已经卖光了****");
     break;
    }
   }
  }  
 }
 public static void main(String[] args) throws Exception{
  Mythread mt = new Mythread();
  new Thread(mt,"售票员A").start();
  new Thread(mt,"售票员B").start();
  new Thread(mt,"售票员C").start();
 }

会观察到票被重复卖了
所以提出同步的概念

同步代码块

使用synchronized关键字实现同步处理
使用同步代码块,为代码加“锁“:

 static class Mythread implements Runnable{
 private int ticket = 3;
  @Override
  public void run() {
   // TODO Auto-generated method stub
   while(true) {//持续卖票
    synchronized(this) {//同步代码块
    if(this.ticket > 0) {
     try {
      Thread.sleep(100);
     } catch (InterruptedException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
     }
     System.out.println(Thread.currentThread().getName()+
       "卖票 ticket:"+this.ticket --);
    }else {
     System.out.println("****票已经卖光了****");
     break;
    }
   }
  }
  }
 }
 public static void main(String[] args) throws Exception{
  Mythread mt = new Mythread();
  new Thread(mt,"售票员A").start();
  new Thread(mt,"售票员B").start();
  new Thread(mt,"售票员C").start();
 }

但是同步会造成处理i性能的下降,也带来一些优点:数据的进程访问安全

同步方法

 static class Mythread implements Runnable{
 private int ticket = 3;
  @Override
  public void run() {
   // TODO Auto-generated method stub
   while(this.sale()) {
   }
  }
  public synchronized boolean sale() {
    if(this.ticket > 0) {
     try {
      Thread.sleep(100);
     } catch (InterruptedException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
     }
     System.out.println(Thread.currentThread().getName()+
       "卖票 ticket:"+this.ticket --);
     return true;
    }else {
     System.out.println("****票已经卖光了****");
     return false;
    }
  }
 }
 public static void main(String[] args) throws Exception{
  Mythread mt = new Mythread();
  new Thread(mt,"售票员A").start();
  new Thread(mt,"售票员B").start();
  new Thread(mt,"售票员C").start();
 }

线程死锁

 static class Book{
  public synchronized void tell(Painting painting) {
   System.out.println("张三对李四说:把画给我,我就给你书,不给画不给书");
   painting.get();
  }
  public synchronized void get() {
   System.out.println("张三获得了李四的画");
  }
 }
 static class Painting{
  public synchronized void tell(Book book) {
   System.out.println("李四对张三说:把书给我,我就给你画,不给书不给画");
   book.get();
  }
  public synchronized void get() {
   System.out.println("李四获得了张三的书");
  }
 }
 static class DeadLock implements Runnable{
  private Book book = new Book();
  private Painting painting = new Painting();
  public DeadLock() {
   // TODO Auto-generated constructor stub
   new Thread(this).start();
   book.tell(painting);
  }
  @Override
  public void run() {
   // TODO Auto-generated method stub
   painting.tell(book);
  }
 }
 public static void main(String[] args) throws Exception{
  new DeadLock();//程序一直等待
 }

综合案例

 static class Message{
  private String title;
  private String content;
  public String getTitle() {
   return title;
  }
  public void setTitle(String title) {
   this.title = title;
  }
  public String getContent() {
   return content;
  }
  public void setContent(String content) {
   this.content = content;
  }  
 }
 
 static class Producer implements Runnable{
  private Message msg = null;
  public Producer(Message msg) {
   // TODO Auto-generated constructor stub
   this.msg = msg;
  }
  @Override
  public void run() {
   // TODO Auto-generated method stub
   for(int x = 0 ;x < 50 ; x++) {
    if(x % 2 == 0) {
     this.msg.setTitle("孔夫子");
     try {
      Thread.sleep(100);
     } catch (InterruptedException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
     }
     this.msg.setContent("儒家学术");
    }else {
     this.msg.setTitle("老子");
     try {
      Thread.sleep(100);
     } catch (InterruptedException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
     }
     this.msg.setContent("道家学术");
    }
   }
  }  
 }
 static class Consumer implements Runnable{
  private Message msg;
  public Consumer(Message msg) {
   // TODO Auto-generated constructor stub
   this.msg = msg;
  }
  @Override
  public void run() {
   // TODO Auto-generated method stub
   for(int x = 0 ; x< 50 ; x++) {
    try {
     Thread.sleep(100);
    } catch (InterruptedException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }
    System.out.println(this.msg.getTitle()+"-->"+this.msg.getContent());
   }
  }
  
 }
 public static void main(String[] args) throws Exception{
  Message msg = new Message();
  new Thread(new Producer(msg)).start();
  new Thread(new Consumer(msg)).start();
 }

可以看到最后是有个
数据错位重复操作的问题

解决数据同步问题

 static class Message{
  private String title;
  private String content;
  public synchronized void set(String title,String content) {
   this.title = title;
   try {
    Thread.sleep(200);
   } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
   this.content = content;
  }
  public synchronized String get() {
   try {
    Thread.sleep(200);
   } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
   return this.title+"-->"+this.content;
  }
  public String getTitle() {
   return title;
  }
  public void setTitle(String title) {
   this.title = title;
  }
  public String getContent() {
   return content;
  }
  public void setContent(String content) {
   this.content = content;
  } 
 }
 
 static class Producer implements Runnable{
  private Message msg = null;
  public Producer(Message msg) {
   // TODO Auto-generated constructor stub
   this.msg = msg;
  }
  @Override
  public void run() {
   // TODO Auto-generated method stub
   for(int x = 0 ;x < 50 ; x++) {
    if(x % 2 == 0) {
     this.msg.set("孔夫子", "儒家学派");
     try {
      Thread.sleep(100);
     } catch (InterruptedException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
     }  
    }else {
     this.msg.set("老子", "道家学派");
     try {
      Thread.sleep(100);
     } catch (InterruptedException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
     }    
    }
   }
  }  
 }
 static class Consumer implements Runnable{
  private Message msg;
  public Consumer(Message msg) {
   // TODO Auto-generated constructor stub
   this.msg = msg;
  }
  @Override
  public void run() {
   // TODO Auto-generated method stub
   for(int x = 0 ; x< 50 ; x++) {
    try {
     Thread.sleep(100);
    } catch (InterruptedException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }
    System.out.println(this.msg.get());
   }
  }
  
 }
 public static void main(String[] args) throws Exception{
  Message msg = new Message();
  new Thread(new Producer(msg)).start();
  new Thread(new Consumer(msg)).start();
 }

Object线程等待和唤醒

方法 描述
public final void wait() throws InterruptedException 线程等待
public final void wait(long timeout) throws InterruptedException 设置等待毫秒数
public final void wait(long timeout,int nanos) throws InterruptedException 设置等待毫秒数和纳秒数
public final void notify() 唤醒第一个等待线程
public final void notifyAll() 唤醒所有等待线程

示例:

 static class Message{
  private String title;
  private String content;
  private boolean flag = true;
  //true表示允许生产,不允许消费
  //false表示允许消费,不允许生产
  //set表示生产过程
  public synchronized void set(String title,String content) {
   if(this.flag == false) {//无法进行生产,等待被消费
    try {
     super.wait();
    } catch (InterruptedException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }
   }
   this.title = title;
   try {
    Thread.sleep(100);
   } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
   this.content = content;
   this.flag = false;
   super.notify();
  }
  
  //get表示消费过程
  public synchronized String get() {
   if(this.flag == true) {//还未生产
    try {
     super.wait();
    } catch (InterruptedException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }
   }
   try {
    Thread.sleep(100);
   } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
   try {
    return this.title +"->"+ this.content;
   } finally {
    // TODO: handle finally clause
    this.flag = true;//继续生产
    super.notify();
   }
  }
 }

优雅地停止线程

停止线程的3个方法:
suspend(),resume(),stop()方法从jdk1.2以来就不推荐使用了,因为这三个方法可能会产生死锁

优雅地停止线程运行

public class testDemo {
 public static boolean flag = true;
 public static void main(String[] args) throws Exception {
  new Thread (() ->{
   long num = 0;
   while(flag) {
    try {
     Thread.sleep(100);
    } catch (InterruptedException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }
    System.out.println(Thread.currentThread().getName()+"正在运行"+num);
   }
  },"执行线程").start();
  Thread.sleep(100);
  flag = false;
 }
}

守护线程

定义:随用户线程存在而存在,随用户线程消失而消失

方法 描述
public final void setDaemon(boolean on) 设置为守护线程
public final boolena isDaemon 判断是否为守护线程
 public static void main(String[] args) {
  Thread userThread = new Thread(() ->
  {
   for(int x = 0 ;x < 2 ;x++) {
    try {
     Thread.sleep(100);
    } catch (InterruptedException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }
    System.out.println(Thread.currentThread().getName()+"正在执行x:"+x);
   }
  },"用户线程");
  Thread daemonThread = new Thread(() ->
  {
   for(int x = 0 ;x < 100 ;x++) {
    try {
     Thread.sleep(100);
    } catch (InterruptedException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }
    System.out.println(Thread.currentThread().getName()+"正在执行x:"+x);
   }
  },"守护线程");
  daemonThread.setDaemon(true);
  userThread.start();
  daemonThread.start();
 }

volatile关键字

定义:多线程中为实现公共资源的操作,通常都是复制变量副本再同步,
而在变量声明时使用volatile关键字,就可以节约复制变量副本和同步的时间

 static class Mythread implements Runnable {
 private volatile int ticket = 3;
  @Override
  public void run() {
   // TODO Auto-generated method stub
   synchronized(this) {
    try {
     Thread.sleep(100);
    } catch (InterruptedException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }
    System.out.println(Thread.currentThread().getName()+"卖票:"+this.ticket --);
   }
  } 
 }
 public static void main(String[] args) {
  Mythread mt = new Mythread();
  new Thread(mt,"售票员A").start();
  new Thread(mt,"售票员B").start();
  new Thread(mt,"售票员C").start();
 }

你可能感兴趣的:(java基础,多线程,java)