线程(二)

简介: 线程(二)

一、线程控制中常用的方法:

①、join方法的使用,代码如下:

  1. package com.weizhaoyang.demo;

  2. /**
  3. * join方法的使用
  4. * 作用:让其主线程等待子线程完成后再执行主线程
  5. */
  6. public class ThreadJoin {
  7.    public static void main(String[] args) {
  8.        System.out.println("main thread start");
  9.        Thread T1 = new Thread(new MyRunnable(), "AAAA");
  10.        T1.start();
  11.        try {
  12.            T1.join();
  13.        } catch (InterruptedException e) {
  14.            e.printStackTrace();
  15.        }
  16.        System.out.println("main thread end");
  17.    }

  18.     static  class  MyRunnable implements Runnable{
  19.         public void run() {
  20.             for(int i=0;i<10;i++){
  21.                 System.out.println(Thread.currentThread().getName()+"执行中");
  22.             }
  23.         }
  24.     }
  25. }

运行的结果如下:

②、设置守护线程

例1、在java中常用的守护线程是GC垃圾回收器, 作用是给其他的线程提供服务的,当主线程程死亡,守护线程自动死亡,只要主线程没有死亡,守护线程会一直去守护它,代码如下:

  1. package com.weizhaoyang.demo;

  2. import java.io.IOException;

  3. /**
  4. * 测试守护线程
  5. */
  6. public class ThreadDaemon {
  7.    public static void main(String[] args) {
  8.        System.out.println("main  Thread start");
  9.        Thread thread = new Thread(new MyRunnable());
  10.        thread.setDaemon(true);//设置守护线程
  11.        thread.start();
  12.       /* try {
  13.            Thread.sleep(5000);
  14.        } catch (InterruptedException e) {
  15.            e.printStackTrace();
  16.        }*/
  17.        //I/O阻塞,等待主线程去输入,一旦输入,然后守护线程就结束了,否则就等待
  18.        try {
  19.            System.out.println("请输入内容");
  20.            System.in.read();
  21.        } catch (IOException e) {
  22.            e.printStackTrace();
  23.        }

  24.        System.out.println("main thread end");
  25.        System.out.println(thread.getState());
  26.    }
  27.    static  class  MyRunnable implements Runnable{
  28.        public void run() {
  29.            for(;;){
  30.                try {
  31.                    Thread.sleep(1000);
  32.                } catch (InterruptedException e) {
  33.                    e.printStackTrace();
  34.                }
  35.                System.out.println(Thread.currentThread().getName()+"执行GC操作准备.....");
  36.            }
  37.        }
  38.    }
  39. }

运行的结果如下:当输入内容和者敲回车的话,守护线程会立刻结束。

守护线程用的场景 :比如某几秒钟想要统计人流量或者流量的数据,这时把它可以设置为守护线程,作用:为其非守护线程(主线程和其他的子线程)提供服务的。

三、sleep方法
主动进
入阻塞状态,调用sleep方法,JDK5以后推荐使用TimeUtil枚举睡眠

四、yield方法

1、执行yield方法,让当前线程设置为就绪状态

2、当完成一个方法的时候,可以将处理器控制权让出去

3、不保证让出去,其他线程就能够马上得到控制权,可能自己又一次拿到了控制权

只是提高了其他的线程拿到时间片的概率提高。

  1. package com.weizhaoyang.demo;

  2. public class ThreadYield {
  3.    public static void main(String[] args) {
  4.          //接口的匿名参数
  5.         Thread t1=new Thread(new Runnable() {
  6.             @Override
  7.             public void run() {
  8.                 for(int i=0;i<5;i++){
  9.                     System.out.println(Thread.currentThread().getName()+"执行"+i);
  10.                 }
  11.             }
  12.         },"AAAA");
  13.        Thread t2=new Thread(new Runnable() {
  14.            @Override
  15.            public void run() {
  16.                for(int i=0;i<5;i++){
  17.                    if(i==0){
  18.                        //当T2线程中的i=2的时候,t1让出来,让t2运行
  19.                        t1.yield();
  20.                    }
  21.                    System.out.println(Thread.currentThread().getName()+"执行"+i);
  22.                }
  23.            }
  24.        },"BBBB");
  25.        //启动线程
  26.        t1.start();
  27.        t2.start();
  28.        t1.yield();
  29.    }
  30. }

运行的结果如下:

五、线程的优先级:proiority,只是说让线程获取时间片的几率大大提高了

范围1-10,中间的优先级为5,推荐使用Thread的三个镜头常量,适应不同的操作系统

代码如下:

  1. package com.weizhaoyang.demo;

  2. /**
  3. * 线程的优先级
  4. */
  5. public class ThreadPriority {
  6.    public static void main(String[] args) {
  7.        Thread t1=new Thread(new MyRunnable(),"AAAA");
  8.        Thread t2=new Thread(new MyRunnable1(),"BBBB");
  9.        t1.setPriority(Thread.MAX_PRIORITY);
  10.        t2.setPriority(Thread.MIN_PRIORITY);
  11.        t1.start();
  12.        t2.start();
  13.    }

  14.    static  class  MyRunnable implements Runnable{
  15.        public void run() {
  16.            for(int i=0;i<5;i++){
  17.                System.out.println(Thread.currentThread().getName()+" 执行中");
  18.            }

  19.        }

  20.    }
  21.    static  class  MyRunnable1 implements Runnable{
  22.        public void run() {
  23.            for(int i=0;i<5;i++){
  24.                System.out.println(Thread.currentThread().getName()+" 执行中");
  25.            }

  26.        }

  27.    }
  28. }

运行如下:线程优先级,提高线程优先于其他线程的几率,并不是按照你设定的去执行。

二、线程同步

当多个线程访问同一个资源时,加synchronized对象对资源进行加锁

①、制造一个线程安全问题的例子:沉睡的话 可以增大线程安全问题几率提高

  1. package com.weizhaoyang.safe;

  2. /**
  3. * 线程安全问题:多个线程共享同一个资源导致的
  4. */
  5. public class ThreadSafe1 {
  6.    public static void main(String[] args) {
  7.        //创建三个卖票窗口
  8.        MyThread  t1=new MyThread("窗口1");
  9.        MyThread  t2=new MyThread("窗口2");
  10.        MyThread  t3=new MyThread("窗口3");
  11.        t1.start();
  12.        t2.start();
  13.        t3.start();
  14.    }
  15.    static   class MyThread  extends Thread{
  16.        public MyThread(String  name){
  17.            super(name);
  18.        }
  19.        //让所有的实例共享这个资源
  20.        private static int  count=10;
  21.        @Override
  22.        public void run() {
  23.             while(count>0){
  24.                 try {
  25.                     Thread.sleep(500);
  26.                 } catch (InterruptedException e) {
  27.                     e.printStackTrace();
  28.                 }
  29.                 String tname = Thread.currentThread().getName();
  30.                 System.out.println(tname+"卖出了"+(count--)+"票");
  31.             }
  32.        }
  33.    }

运行结果如下:这就是在睡眠的时候出现了线程的安全性问题,本来是10张票,却卖出12张票。也就是说在阻塞的过程中,窗口1,2同时拿到了还没有减的这张票(0),而且这个“0”票是超卖的票,原因当窗口3进来拿到票了,而没有减,当窗口2进来的时候,把票减了,这时窗口2和窗口1都拿到了“0”票,这就出现了线程的安全性的问题,没有保证原子性。

如果不加static的话,三个窗口都会分别卖出10张票,因为每创建一个对象就会有一个count变量为10的成员,属于实例中的成员,局部变量不会出现线程安全的问题。

上面使用的是继承的方式,如果用接口的话,更好,因为接口是多实现的,继承是单继承的

例子②,代码如下:

  1. package com.weizhaoyang.safe;

  2. public class ThreadSafe2 {
  3.    //让所有的实例共享这个资源
  4.    private static int  count;

  5.    public static void main(String[] args) {
  6.        Thread t1=new Thread(new MyThread());
  7.        Thread t2=new Thread(new MyThread());
  8.        t1.start();
  9.        t2.start();
  10.        try {
  11.            t1.join();
  12.            t2.join();
  13.        } catch (InterruptedException e) {
  14.            e.printStackTrace();
  15.        }
  16.        System.out.println("count="+count);
  17.    }
  18.    static   class MyThread  implements Runnable{
  19.        @Override
  20.        public void run() {
  21.           for(int i=0;i<1000000;i++){
  22.               count++;
  23.           }
  24.        }
  25.    }
  26. }

运行的结果如下:这也是线程的安全的问题,说明很多数据出现了线程的安全性的问题。

解决方案:

用到线程同步操作:既然保证count的原子性

synchronized有三种加锁的方式,在jdk1.5的时候用的比较多,但是现在已经被并发编程的包给替代掉了

1、同步块:

synchronized:保证在同一个时间片上不能有其他线程同时执行 。

当其中一个线程拿到锁之后,就执行count++,然后执行完,就释放锁,然后另一个线程来执行,否则继续等待锁。并且仅有一个线程拿到锁。

同步块里传的参数是对象,代表锁的标识。

  1. package com.weizhaoyang.sync;

  2. import com.weizhaoyang.safe.ThreadSafe2;

  3. /**
  4. * 使用同步块解决线程安全的问题
  5. */
  6. public class SyncBlock {
  7.    //让所有的实例共享这个资源
  8.    private static int  count;
  9.    private  static  Object lock=new Object();

  10.    public static void main(String[] args) {
  11.        Thread t1=new Thread(new MyThread());
  12.        Thread t2=new Thread(new MyThread());
  13.        t1.start();
  14.        t2.start();
  15.        try {
  16.            t1.join();
  17.            t2.join();
  18.        } catch (InterruptedException e) {
  19.            e.printStackTrace();
  20.        }
  21.        System.out.println("count="+count);
  22.    }
  23.    static   class MyThread  implements Runnable{
  24.        @Override
  25.        public void run() {
  26.            for(int i=0;i<1000000;i++){
  27.                synchronized (lock){
  28.                    count++;
  29.                }
  30.            }
  31.        }
  32.    }
  33. }

结果如下:

2、在实例上加锁

  1. package com.weizhaoyang.sync;

  2. /**
  3. * 使用同步关键字枷锁对象的实例方法
  4. */
  5. public class SynInstance {
  6.    //让所有的实例共享这个资源
  7.    private static int  count;
  8.    public static void main(String[] args) {
  9.        MyThread myThread=new MyThread();

  10.        Thread t1=new Thread(myThread);
  11.        Thread t2=new Thread(myThread);
  12.        t1.start();
  13.        t2.start();
  14.        try {
  15.            t1.join();
  16.            t2.join();
  17.        } catch (InterruptedException e) {
  18.            e.printStackTrace();
  19.        }
  20.        System.out.println("count="+count);
  21.    }
  22.    static   class MyThread  implements Runnable{
  23.        public  synchronized   void  trace(){
  24.                count++;
  25.        }
  26.        @Override
  27.        public void run() {
  28.            for(int i=0;i<1000000;i++){
  29.                   trace();
  30.            }
  31.        }
  32.    }
  33. }

运行的结果如下:

3、类锁,代码如下:

  1. package com.weizhaoyang.sync;

  2. /**
  3. * 使用同步关键字枷锁对象的实例方法
  4. */
  5. public class SynInstance {
  6.    //让所有的实例共享这个资源
  7.    private static int  count;
  8.    public static void main(String[] args) {


  9.        Thread t1=new Thread(new MyThread());
  10.        Thread t2=new Thread(new MyThread());
  11.        t1.start();
  12.        t2.start();
  13.        try {
  14.            t1.join();
  15.            t2.join();
  16.        } catch (InterruptedException e) {
  17.            e.printStackTrace();
  18.        }
  19.        System.out.println("count="+count);
  20.    }
  21.    static   class MyThread  implements Runnable{
  22.        public  static synchronized   void  trace(){
  23.                count++;
  24.        }
  25.        @Override
  26.        public void run() {
  27.            for(int i=0;i<1000000;i++){
  28.                   trace();
  29.            }
  30.        }
  31.    }
  32. }

运行的结果如下:

一般使用类锁比较好

总结:不管在对象上加锁,类上加锁,实例上加锁,只要持有的是同一把锁就可以解决线程 安全的问题,明天写重入锁,非公平,公平,读写锁。

相关文章
|
10小时前
|
监控 安全 Java
线程(一)
线程(一)
|
3月前
|
NoSQL Java 应用服务中间件
线程不够用怎么办?
### 并发编程挑战与解决方案概览 - 多线程导致线程爆炸,浪费CPU及可能导致JVM崩溃。线程池缓解问题,但仍有阻塞IO的效率低下。 - 非阻塞IO(如servlet3.1/Tomcat)和事件驱动(Reactive/Future)减少线程使用,但学习曲线陡峭。 - 轻量级线程如Netty、Spring Flux和虚拟线程(Java Loom)提升性能,但普及尚需时日。Java21引入虚拟线程,有望成未来性能关键。
165 10
|
4月前
|
存储 安全 Java
C++线程浅谈
C++线程浅谈
|
4月前
|
C#
C#线程初步
C#线程初步
31 0
|
算法 安全 程序员
线程小练习
线程小练习
|
算法 NoSQL Java
02.关于线程你必须知道的8个问题(上)
大家好,我是王有志,欢迎来到《Java面试都问啥?》。 今天我们来一起看看在面试中,关于线程各大公司大都喜欢问哪些问题。
94 1
02.关于线程你必须知道的8个问题(上)
|
Java Linux 程序员
04.关于线程你必须知道的8个问题(下)
大家好,我是王有志。今天是Java面试中线程问题的最后一部分内容,包括我们来聊同步与互斥,线程的本质,调度,死锁以及线程的优缺点等问题。
105 1
04.关于线程你必须知道的8个问题(下)
|
Java
线程理解
个人学习理解
72 0
|
传感器 存储 自动驾驶
(6)线程
(6)线程
92 0
|
Java 编译器 Linux
初识 线程
初识 线程
97 0
初识 线程