Java多线程(中)

线程状态

方法
  • setPriority(int new Priority)更改线程的优先级
  • static void sleep(long millis)在指定的毫秒数内让当前正在执行的线程休眠
  • void join()等待该线程终止
  • static void yield()暂停当前正在执行的线程对象,并执行其他线程
  • void interrupt()中断线程,不建议用这个方式
  • boolean isAlive()测试线程是否处于活动状态
停止线程
/*
测试stop
1.建议线程正常终止-->利用次数,不建议死循环
2.建议使用标志位
3.不要使用stop或destroy等过时或者JDK不建议使用的方法
*/

public class TestStop implements Runnable{
  //1.设置一个标志位
  private boolean flag = true;
  
  public void run(){
    int i = 0;
    while(flag){
      System.out.println("run... Thread"+i++);
    }
  }
  //2.设置一个公开的方法停止线程,转换标志位
  public void stop(){
    this.flag = false;
  }
  
  piblic static void main(String[] args){
    TestStop testStop = new TestStop();
    new Thread(testStop).start();
    
    for(int i = 0; i<1000; i++){
      System.out.println("main"+i);
      if(i = 900){
        //调用stop方法转换标志位,让线程停止
        testStop.stop();
        System.out.println("Thread is stop");
      }
    }
  }
}
线程休眠

⚠️每个对象都有一个锁,sleep不会释放锁

 /*
 模拟网络延时:放大问题的发生性
 */
//模拟倒计时
public class TestSleep{
  public static void main(String[] args){
    try{
      tenDown();
    }catch(InterruptedException e){
      e.printStackTrace();
    }
  }
  public void tenDown() throws InterrupedException{
    int num = 10;
    while(true){
      Thread.sleep(1000);
      System.out.println(num--);
      if(num <=0){
        break;
      }
    }
  }
}
线程礼让yield

让当前正在执行的线程暂停,但不阻塞

从运行转为就绪

让CPU重新调度,礼让不一定成功

public class TestYield{
  public static void main(String[] args){
    MyYield myYield = new MyYield();
    
    new Thread(myYield,"a").start();
    new Thread(myYield,"b").start();
  }
}
class MyYield implements Runnable{
  public void run(){
    System.out.println("START");
    Thread.yield();//礼让
    System.out.println("END");
  }
}
线程强制执行join

插队

public class TestJoin implements Runnable{
  publlic void run(){
    for(int i=0; i<100; i++){
      System.out.println("VIP is coming " + i);
    }
  }
  
  public static void main(String[] args){
    //启动线程
    TestJoin testJoin = new TestJoin();
    Thread thread = new Thread(testJoin);
    thread.start();
    
    //主线程
    for(int i=0; i<1000; i++){
      if(i == 200){
         thread.join();//插队
      }
      System.out.println("main "+i);
    }
  }
}
观测线程状态
//观察测试线程的状态
public class TsetState{
  public static void main(String[] args) throws InterruptedExecption{
    Thread thread = new Thread(()->{
      for(int i=0; i<5; i++){
        try{
          Thread.sleep(1000);
        }catch(InterruptedException e){
          e.printStackTrace();
        }
      }
      System.out.println("-------");
    });
    
    //观察状态
    Thread.State state = thread.state();
    System.out.println(state);//NEW
    
    //观察启动后
   	thread.start();
    state = thread.state();
    System.out.println(state);//RUN
    
    while(state != Thread.State.TERMINATE){//只要线程不停止,就一直输出
    	Thread.sleep(100);
      state = thread.state();
      System.out.println(state);
    }
  }
}

线程的优先级

priority优先级,从1到10

优先级高了也不一定先执行,看CPU怎么调取,但是优先级高了权重就大,获得调度的概率更高

public class TestPriority{
  public static void main(String[] args){
    //主线程默认优先级
    System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());
    
    MyPriority myPriority = new MyPriority();
    Thread t1 = new Thread(myPriority);
    Thread t2 = new Thread(myPriority);
    Thread t3 = new Thread(myPriority);
    Thread t4 = new Thread(myPriority);
    Thread t5 = new Thread(myPriority);
    Thread t6 = new Thread(myPriority);
    
    //先设置优先级,再启动
    t1.start();
    t2.serPriority(1);
    t2.start();
    t3.serPriority(4);
    t3.start();
    t4.serPriority(Thread.MAX_PRIORITY);//10
    t4.start();
    t5.serPriority(-1);//报错
    t5.start();
    t6.serPriority(11);//报错
    t6.start();
  }
}
class MyPriority implements Runnable{
  public void run(){
    System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());
  }
}

守护线程daemon

线程分为用户线程和守护线程 eg:用户线程main()

虚拟机必须确保用户线程执行完毕

虚拟机不用等待守护线程执行完毕 eg:后台记录操作日志、监控内存、垃圾回收等待

thread.setDaemon(true);默认为false,即用户线程,正常的线程都是用户线程

线程同步机制

多个线程操作同一个资源

并发:同一个对象被多个线程同时操作

线程同步其实就是一种等待机制,多个需要同时访问此对象的线程进入这个对象的等待池形成队列,等待前面线程使用完毕,下一个线程再使用

形成条件:队列+锁

为了保证数据在方法中被访问时的正确性,在访问时加入锁机制synchronized,当一个线程获得对象的排它锁,独占资源,其他线程必须等待,使用后释放锁即可

存在问题:提高安全,但是损失性能

每个线程都在自己的工作内存进行数据交互,如果操作不当容易造成数据的错误

⚠️线程不安全的集合:ArrayList 把数据放到同一个位置,就替换掉了

同步方法

synchronized方法和synchronized块

每个对象一把锁,每个synchronized方法都必须获得调用该方法的对象的锁才能执行,否则线程会阻塞,方法一旦执行就独占该锁

//同步方法
public class TestTicket{
  public static void main(String[] args){
    BuyTicket buyer = new BuyTicket();
    
    new Thread(nuyer,"jack").start();
    new Thread(buyer,"tomy").start();
    new Thread(buyer,"namy").start();
  }
}

class BuyTicket implements Runnable{
  private int ticketNum = 10;
  boolean flag = true; //外部停止方式
  
  public void run(){
    while(true){
      try{
        buy();
      }catch(InterruptedException e){
        e.printStackTrace();
      }
    }
  }
  //synchronized同步方法,锁的是方法的调用者,锁的是this 
  private synchronized void buy() throws InterruptedException{
    //判断是否有票
    if(ticketNum <= 0){
      flag = false;
      return;
    }
    //模拟延时
    Thread.sleep(1000);
    //买票
    System.out.println(Thread.currentThread().getName() + " get "+ticketNum--);
  }
}
//同步块
public class UnsafeList{
  public static void main(String[] args){
    List<String> list = new ArrayList<String>();
    for(int i=0; i<10000; i++){
      new Thread(()->{
        //锁的对象就是变化的量,需要进行增删改的
        synchronized(list){
          list.add(Thread.currentThread().getName());
        }
      }).start();
    }
    try{
      Thread.sleep(3000);
    }catch(InterruptedException e){
      e.printStackTrace();
    }
    System.out.println(list.size());
  }
}
posted @ 2021-02-18 12:54  GladysChloe  阅读(40)  评论(0)    收藏  举报