多线程学习简记

第一次
进程:正在进行中的程序(直译);
线程:就是进程中的一个负责程序执行的控制单元(执行路径);
一个进程中可以有多个线程的执行,称之为多线程;
一个进程当中至少要有一个线程;
开启多个线程是为了同时运行多部分代码;
每一个线程都有自己运行的内容,这个内容可以称之为线程要执行的任务;
多线程的好处:解决了多部分同时运行的问题;
多线程的弊端:线程太多会导致效率的降低;
其实应用程序的执行都是cpu在做着快速的切换完成的。这个切换时随机的;
JVM启动时就启动了多个线程,至少有两个线程可以分析的出来。
1、执行main函数的线程;
        该线程的任务代码都定义在main函数中。
2、负责垃圾回收的线程;
 
 
第二次
创建线程的目的是为了开启一条执行路径,取运行指定的代码和其他代码实现同时运行,而运行的指定代码就是这个执行路径的任务
jvm创建的主线程的任务都定义在了主函数中,而自定义的线程的任务哪里?在Thread类用户描述线程,线程需要任务的,所以Thread类也对任务的描述,这个任务就通过Thread类中的run方法来体现,也就是说,run方法就是封装自定义线程运行任务的函数。
run方法中定义的就是线程中要运行的任务代码。
开启线程是为了运行指定的代码,所以只有继承Thread类,并复写run方法,将运行的代码定义在run方法中即可。
两种方式:集成Thread类
                实现Runable接口
 
第三次     2020年6月29日19:58:05
可以通过Thread的getName获取线程的名称 Thread-编号
多线程如果开启了一条线程,则开启了一条执行路径,每条线程都已自己的栈,然后压栈弹栈
 
线程多种状态
创建      就绪    执行    结束    阻塞
多线程学习简记_第1张图片
cpu的执行资格:可以被cpu处理,在处理队列中排队
cpu的执行权:正在被cup处理
 
实现Runnable接口的好处:
1、将线程的任务从线程的子类中分离出来,进行了单独的封装。
2、避免了java单继承的局限性
所以,创建线程的第二种方式较为常用
 
  public synchronized void start() {
        
        if ( threadStatus != 0)
            throw new IllegalThreadStateException();
       
        group.add( this);
        boolean started = false;
        try {
            start0();
            started = true;
        } finally {
            try {
                if (! started) {
                    group.threadStartFailed( this);
                }
            } catch (Throwable ignore) {
                
            }
        }
    }
    private native void start0();
 
这里的start0()用了 native ,这个关键字表示调用本机的操作系统函数,因为多线程需要底层操作系统的支持。
 
第四次 2020年6月30日20:17:16
线程安全问题:
1、多个线程在操作共享的数据。
2、操作共享数据的线程代码有多条。
当一个线程在执行操作共享数据的多条代码过程中,其他线程参与了运算,就会导致线程安全问题的产生。
解决思路:就是将多条操作共享数据的线程代码封装起来,当有线程在执行这些代码的时候,其他线程不可以参与运算
synchronized
同步的好处:解决了线程的安全问题;
同步的弊端:相对降低了效率,因为同步外的线程都会判断同步锁
 
同步的前提:同步中必须有多个线程并使用同一个锁;
 
需求:储户两个,每个都到银行存钱,每次存100 ,共存3次
public class BankDemo {
      public static void main(String[] args) {
           Cus c = new Cus();
           Thread  t1 = new Thread( c);
           Thread  t2 = new Thread( c);
            t1.start();
            t2.start();
     }
}
class Bank{
      private int sum;
      public synchronized void add( int num) { //同步函数
            sum= sum+ num;
           System. out.println( "sum:"+ sum);
     }
}
class Cus implements Runnable{
     Bank b = new Bank();
      @Override
      public void run() {
            for ( int i = 0; i < 3; i++) {
                       b.add(100);
           }          
     }
}
 
同步函数使用的锁:当前对象 即this
同步函数和同步代码块的区别:
同步函数的锁是固定的this;同步代码块的锁是任意的;
建议使用同步代码块;
 
静态同步函数锁:不用this,用this.getClass();该函数所属字节码对象 可以用getClass方法获取,可以用当前类名.class表示;
 
第五次 2020年7月2日20:07:37
多线程下的单例
public class SingleDemo {
      public static void main(String[] args) {
     }
}
//饿汉式
class Single{
      private static final Single s = new Single();
      private Single() {}
      public static Single getInstance() {
            return s;
     }
}
//懒汉式
class Single1{
      private static Single1 s = null;
      private Single1() {}
     
      public static Single1 getInstance() {
            if( s== null) { //解决效率问题
                 synchronized (Single1. class) { //解决安全问题
                       if( s== null) {   
                            s= new Single1();
                      }
                }
           }
            return s ;
     }
}
第六次 2020年7月5日08:34:30 等待环唤醒机制的使用
死锁:常见情景之一:同步的嵌套
public class DeadLoackTest {
      public static void main(String[] args) {
           Test a = new Test();
           Thread t1 = new Thread( a);
           Thread t2 = new Thread( a);
            t1.start();
            try {
                Thread. sleep(1);
           } catch (InterruptedException e) {
                 e.printStackTrace();
           }
            a. flag = false;
            t2.start();
     }
}
class Test implements Runnable {
      public boolean flag = true;
      private static final Object locka = new Object();
      private static final Object lockb = new Object();
     Test() {
     }
      @Override
      public void run() {
            if ( flag) {
                 while ( true) {
                       synchronized ( locka) {
                           System. out.println( "if locka ....");
                            synchronized ( lockb) {
                                 System. out.println( "if lockb ....");
                           }
                      }
                }
           } else {
                 while ( true) {
                       synchronized ( lockb) {
                           System. out.println( "else lockb ....");
                            synchronized ( locka) {
                                 System. out.println( "else locka ....");
                           }
                      }
                }
           }
     }
}
线程间通信:多个线程在处理同一资源,但是任务却不同。
等待唤醒机制:涉及的方法    1,wait();       让线程处于冻结状态,被wait的线程会被存储到线程池中
                                          2,notify();    唤醒线程池中的一个线程(任意)
                                          3,notifyAll();    唤醒线程 池中所有线程
这些方法都必须都定义在同步中,因为这些方法是用于操作线程状态的方法,必须要明确到底操作的是哪个锁上的线程;
为什么操作线程的方法wait notify notifyAll 定义在Object类中
因为这些方法都是监视器的方法。监视器其实就是锁,锁可以是任意的对象,任意的对象调用方式一定定义在Object类中;
public class ResourceDemo {
      public static void main(String[] args) {
//         创建资源
           Resource r = new Resource();
//         创建任务
           Input input = new Input( r);
           Output outPut = new Output( r);
//         创建线程,执行路径
           Thread t1 = new Thread( input);
           Thread t2 = new Thread( outPut);
//         开启线程
            t1.start();
            t2.start();
     }
}
class Resource{
      String name;
      String sex;
      boolean flag = false;
     
     
}
class Input implements Runnable{
     Resource  r ;
      public Input(Resource r){
            this. r= r;
     }    
      @Override
      public void run() {
            int x =0;
            while( true) {
                 synchronized ( r) {
                       if( r. flag)
                            try {
                                  r.wait();
                           } catch (InterruptedException e) {
                                  e.printStackTrace();
                           }
                 if( x==0) {
                       r. name= "mike";
                       r. sex= "man";
                } else {
                       r. name= "丽丽";
                       r. sex= "女女女";
                }
                 x=( x+1)%2;
                 r. flag= true;
                 r.notify(); //可空唤醒一次
                }
           }
           
     }
     
}
class Output implements Runnable{
     Resource  r ;
     
      public Output(Resource r) {
            this. r= r;
     }
      @Override
      public void run() {
            int a =0;
            while( a<=10) {
                 synchronized ( r) {
                       if(! r. flag)
                            try {
                                  r.wait();
                           } catch (InterruptedException e) {
                                  e.printStackTrace();
                           }
                      System. out.println( r. name+ "...."+ r. sex);
                       r. flag= false;
                       r.notify();
                }
                 a++;
           }
     }
}
 
代码优化:
package com.mly.test.duoxiancheng;
public class ResourceDemo {
      public static void main(String[] args) {
//         创建资源
           Resource r = new Resource();
//         创建任务
           Input input = new Input( r);
           Output outPut = new Output( r);
//         创建线程,执行路径
           Thread t1 = new Thread( input);
           Thread t2 = new Thread( outPut);
//         开启线程
            t1.start();
            t2.start();
     }
}
class Resource {
      private String name;
      private String sex;
      private boolean flag = false;
      public synchronized void set(String name, String sex) {
            if ( flag)
                 try {
                       this.wait();
                } catch (InterruptedException e) {
                       e.printStackTrace();
                }
            this. name = name;
            this. sex = sex;
            flag = true;
            this.notify();
     }
      public synchronized void out() {
            if (! flag)
                 try {
                       this.wait();
                } catch (InterruptedException e) {
                       // TODO Auto-generated catch block
                       e.printStackTrace();
                }
           System. out.println( name + "...." + sex);
            flag = false;
            this.notify();
     }
}
class Input implements Runnable {
     Resource r;
      public Input(Resource r) {
            this. r = r;
     }
      @Override
      public void run() {
            int x = 0;
            while( true) {
                 if ( x == 0) {
                       r.set( "mike", "man");
                } else {
                       r.set( "丽丽", "女女女");
                }
                 x = ( x + 1) % 2;
           }
     }
}
class Output implements Runnable {
     Resource r;
      public Output(Resource r) {
            this. r = r;
     }
      @Override
      public void run() {
            int a = 0;
            while ( a <= 10) {
                 r.out();
                 a++;
           }
     }
}
 
多生产者,多消费者
if判断标记只有一次,会导致不该运行的线程运行了,出现了数据错误的情况;
while判断标记,解决线程获取执行权后,是否要运行;
 
notify:只能唤醒一个线程,如果本方唤醒本方,没有意义,而且while判断标记+notify会导致死锁
notifyAll解决,本方线程一定会唤醒对方线程的问题。
 
package com.mly.test.duoxiancheng;
/**
 *    生产者,消费者
 *    多生产者    多消费者
 *
 */
public class ProducerCustomerDemo {
      public static void main(String[] args) {
           Resrouce r = new Resrouce();
           Producer p = new Producer( r);
           Customer c = new Customer( r);
           Thread t0 = new Thread( p);
           Thread t1 = new Thread( p);
           Thread t2 = new Thread( c);
           Thread t3 = new Thread( c);
            t0.start();
            t1.start();
            t2.start();
            t3.start();
     }
}
class Producer implements Runnable{
     
      private Resrouce r ;
     
      public Producer(Resrouce r) {
            this. r= r;
     };
      @Override
      public void run() {
            while( true) {
                 r.set( "烤鸭");
           }
     }
     
}
class Customer implements Runnable{
      private Resrouce r;
      public Customer(Resrouce r) {
            this. r= r;
     }
      @Override
      public void run() {
            while( true) {
                 r.out();
                
           }
           
     }
}
class Resrouce {
      private String name;
      private int count=1;
      private boolean flag = false;
      public synchronized void set(String name) {
            while( flag)
                 try {
                       this.wait();
                } catch (InterruptedException e) {
                       // TODO Auto-generated catch block
                       e.printStackTrace();
                }
           
            this. name= name+ count;
            count++;
           System. out.println(Thread. currentThread().getName()+ ".生产者..."+ this. name);
            flag= true;
            this.notifyAll();
           
     }
      public synchronized  void out() {
            while(! flag)
                 try {
                       this.wait();
                } catch (InterruptedException e) {
                       e.printStackTrace();
                }
           System. out.println(Thread. currentThread().getName()+ ".消费者______"+ this. name);
            this. flag= false;
            this.notifyAll();
     }
}
 
 
同步代码块对于锁的操作是隐式的;
Lock lock = new ReentrantLoack():    jdk1.5以后将同步和锁封装成 了对象,并将操作锁的隐式方式定义到了该对象中,将隐式动作变成了显示动作。
Lock接口:出现替代了同步代码块或者同步函数,将同步的隐式锁操作变成现实锁操作,同时更为灵活,可以一个锁上加上多组监视器。
lock()获取锁
unlock()释放锁,通常需要定义在finally代码块中
condition接口:出现替代了Object中的wait notify notifyall方法,讲这些监视器方法单独进行了封装,变成了condition监视器对象,可以任意锁记性组合
使用lock
/**
 *    生产者,消费者
 *    多生产者    多消费者
 *
 */
public class ProducerCustomerDemo {
      public static void main(String[] args) {
           Resrouce r = new Resrouce();
           Producer p = new Producer( r);
           Customer c = new Customer( r);
           Thread t0 = new Thread( p);
           Thread t1 = new Thread( p);
           Thread t2 = new Thread( c);
           Thread t3 = new Thread( c);
            t0.start();
            t1.start();
            t2.start();
            t3.start();
     }
}
class Producer implements Runnable{
     
      private Resrouce r ;
     
      public Producer(Resrouce r) {
            this. r= r;
     };
      @Override
      public void run() {
            while( true) {
                 r.set( "烤鸭");
           }
     }
}
class Customer implements Runnable{
      private Resrouce r;
      public Customer(Resrouce r) {
            this. r= r;
     }
      @Override
      public void run() {
            while( true) {
                 r.out();
           }
     }
}
class Resrouce {
      private String name;
      private int count=1;
      private boolean flag = false;
     Lock lock = new ReentrantLock();
      //   通过已有的锁获取两组监视器    一组生产者监视器,一组消费者监视器
     Condition con1= lock.newCondition();
     Condition con2= lock.newCondition();
     
      public  void set(String name) {
            lock.lock();
            try {
                 while( flag)
                       try {
                            con1.await();
                      } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                      }
                 this. name= name+ count;
                 count++;
                System. out.println(Thread. currentThread().getName()+ ".生产者..."+ this. name);
                 flag= true;
                 con2.signal();
           } catch (Exception e) {
           } finally {
                 lock.unlock();
           }
     }
      public  void out() {
            lock.lock();
            try {
                 while(! flag)
                       try {
                            con2.await();
                      } catch (InterruptedException e) {
                            e.printStackTrace();
                      }
                System. out.println(Thread. currentThread().getName()+ ".消费者______"+ this. name);
                 this. flag= false;
                 con1.signal();
           } catch (Exception e) {
           } finally {
                 lock.unlock();
           }
     }
 
wait和sleep的区别:
1、wait可以指定时间,可以不指定,sleep必须指定时间。
2、在同步中时,对于cpu的执行权和执行锁的处理不同:
    wait:释放执行权,释放锁
    sleep:释放执行权,不释放锁
 
void show()
{
    synchronized(this){    //t0 t1 t2
        wait();     //t0  t1
    }
}
 
void method()
{
    synchronized(this){
   //     wait();    
        notifyAll();
    }
}
 
 
停止线程:
1、stop方法;
2、run方法结束;
怎么控制线程的任务结束呢?
任务中都会有循环结构,只要控制住循环就可以结束任务。
控制循环通常用定义标记来完成  while()
但是如果线程处于冻结状态,无法读取标记,如何结束呢?
可以使用interrupt()方法将线程从冻结状态强制恢复到运行状态中来,让线程具备cpu的执行资格,但是强制动作会发生中断异常,记得要处理。
 
package com.mly.test.duoxiancheng;
public class StopThreadDemo {
      public static void main(String[] args) {
           StopThread stop= new StopThread();
           Thread t1 = new Thread( stop);
           Thread t2 = new Thread( stop);
            t1.start();
            t2.start();
            int num=1;
            for(;;) {
                 if(++ num==50) {
                       t1.interrupt(); //将线程从冻结状态强制恢复到运行状态中来,让线程具备 cpu 执行资格
                       t2.interrupt();
                       break;
                 }
                 System. out.println( "main...."+ num);
            }
            System. out.println( "over");
     }
}
class StopThread implements Runnable{
      private boolean flag = true;
      public void setFlag() {
            this. flag= false;
     }
      @Override
      public synchronized void run() {
            while( flag) {
                 try {
                      wait();
                } catch (Exception e) {
                       System. out.println(Thread. currentThread().getName()+ "----"+ e);
                       flag= false;
                }
                System. out.println(Thread. currentThread().getName()+ "----");
           }
     }
}
 
守护线程
如果所有前台线程结束,后台线程无论出于任何状态都会结束
 
 
join方法  等待该线程终止,主线程等待t1线程执行完之后会再执行。
public class JoinDemo {
      public static void main(String[] args) {
           DemoJ d = new DemoJ();
           Thread t1 = new Thread( d);
           Thread t2 = new Thread( d);
            t1.start();
            t2.start();
            try {
                 t1.join();  //t1线程要申请加入进来,运行;临时加入线程运算时可以使用join方法
           } catch (InterruptedException e) {
                 e.printStackTrace();
           }
            for ( int i = 0; i < 50; i++) {
                System. out.println(Thread. currentThread().getName()+ "....."+ i);
           }
     }
}
class DemoJ implements Runnable{
      @Override
      public void run() {
            for ( int i = 0; i < 100; i++) {
                System. out.println(Thread. currentThread().getName()+ "...."+ i);
           }
     }
}
 
优先级,暂停方法
package com.mly.test.duoxiancheng;
public class JoinDemo {
      public static void main(String[] args) {
           DemoJ d = new DemoJ();
           Thread t1 = new Thread( d);
           Thread t2 = new Thread( d);
            t1.start();
            t2.start();
//         t2.setPriority(Thread.MAX_PRIORITY); //线程设置优先级
            try {
                 t1.join();  //t1线程要申请加入进来,运行;临时加入线程运算时可以使用join方法
           } catch (InterruptedException e) {
                 e.printStackTrace();
           }
            for ( int i = 0; i < 50; i++) {
                System. out.println(Thread. currentThread().getName()+ "....."+ i);
           }
     }
}
class DemoJ implements Runnable{
      @Override
      public void run() {
            for ( int i = 0; i < 100; i++) {
                System. out.println(Thread. currentThread().toString()+ "...."+ i);
                Thread. yield(); //     线程暂停
           }
     }
}
 
一些题目
1、//   如果错误,错发生在哪一行? 发生在Test1
class Test1 implements Runnable{
      public void run(Thread d) {
     }
}
2、运行结果?     subThread run  以子类为主
public class ThreadTest {
      public static void main(String[] args) {
            new Thread( new Runnable() {
                 public void run() {
                      System. out.println( "runnable run ");
           }}) {
                 public void run() {
                      System. out.println( "subThread run");
                }
           }.start();
     }
}
 
代码连接: https://github.com/menglingyang/DailyPractive.git
 

你可能感兴趣的:(java)