多线程总结一


总结:
多线程创建的4中方式: Thread Runnable Callable 线程池

加锁的方式: synchronized  
                  ReentrantLock    lock unlock

生产者消费者模式,线程的等待唤醒通知机制: (用while防止虚假唤醒)
synchronized  wait() notifyall()
ReentrantLock  Condition的await() 和signalAll()

线程的锁机制:  
                      static synchronized 和 synchronized
                       所有的 静态同步方法用的是同一把锁,类对象本身。
             所有静态同步方法用的是同一把锁,实例对象本身
线程轮询的时候定制顺序访问:
          condition1.await()   condition2.signal()
读写锁:ReentrantReadWriteLock 
       ReentrantReadWriteLock rw = new ReentrantReadWriteLock();
           rw .writeLock().lock();
           rw .writeLock().unlock();
          rw .readLock().lock();
           rw .readLock().lock();

Lock的模板:  
lock.lock();
          try {
            //判断、干活、唤醒
          } finally {
              lock.unlock();
          }

 线程池:  利用Executors得到ExecutorService
                      Executors . newFixedThreadPool(5) //5个线程的线程池
                Executors.newSingleThreadExecutor()//一个线程
                Executors. newCachedThreadPool ()//随机线程
                Executors. newScheduledThreadPool (5)//5个线程,有时间间隔

多线程之间按顺序调用 A -> B -> C
 *AA打印5次,BB打印10次,CC打印15次
 *接着
 *AA打印5次,BB打印10次,CC打印15次
 * ......来10轮
分析:三个AA,BB,CC线程都进行10次循环,线程i=1先抢到,number=1先进入AA线程的方法中,当AA循环打印了5次后,利用condition2.signal()唤醒了condition2.await()的



1.售票问题:
class Tikect {
      // 高内聚,低耦合
      int number = 30;
      ReentrantLock lock = new ReentrantLock();
      public void sale() {
           // 票具有的方法
           lock .lock();
           try {
               if ( number >0){
                   
                   System. out .println(Thread. currentThread ().getName() + "\t还剩" + number + "\t卖出第" +(-- number ));
              }
          } catch (Exception e ) {
          } finally {
               lock .unlock();
          }
     }
}
/**
 *
 * 三个售票员 三个窗口 卖30张票 多线程问题
 *
 * 线程 解决 资源类 高内聚,低耦合
 *
 *
 *
 * @author 77585211
 *
 */
public class Test1 {
      public static void main(String[] args ) {
          Tikect tikect = new Tikect();
           new Thread( new Runnable() {
               @Override
               public void run() {
               for ( int i = 0; i < 50; i ++) {
                   
                 tikect .sale();
              }
              }
          }, "售票員A" ).start();
           new Thread( new Runnable() {
               @Override
               public void run() {
                     for ( int i = 0; i < 50; i ++) {
                             
                      tikect .sale();
                   }
              }
          }, "售票員B" ).start();
           new Thread( new Runnable() {
               @Override
               public void run() {
                     for ( int i = 0; i < 50; i ++) {
                             
                      tikect .sale();
                   }
              }
          }, "售票員C" ).start();
     }
}

总结1.:ReentrantLock比Synconized好的地方是,Syconized是锁掉整个方法,而ReentrantLock是锁住几行。
lock.lock()方法要放在try..catch之前

2.创建多线程的方法之一 : 实现Callable接口

/**
 * 根据 Callable <V> 接口创建多线程 
 * @author 77585211
 *
 *
 *当有一件事情特别浪费时间,可以用FutureTask,用于异步获取结果
 *线程  操作  资料类
 *高内聚 低耦合
 *
 */
public class Test2 {
      public static void main(String[] args ) throws InterruptedException, ExecutionException{
           //主方法中不写逻辑
          FutureTask<Integer>  ft = new FutureTask<Integer>( new Call());
           new Thread( ft , "AA" ).start();
          System. out .println( "*********main主方法1" );
           int result = ft .get();
          System. out .println( "调用FutureTask中的方法:" + result );
     }
}
class Call implements Callable<Integer>{
           @Override
           public Integer call() throws Exception {
              
              System. out .println( "*****call()调用了" );
              
              Thread. sleep (2000);
              
               return 123;
          }
          
     }
总结2: FutureTask<V>

1.多用于耗时的计算,主线程执行完之后,再去取结果
2.只计算一次
3.仅在计算完后才能得到结果,如果计算尚未完成就取数据,将会线程堵塞状态


3.多线程实现交替(一个减,一个加)
题目:现在有两个线程,可以操作初始值为0的数,实现一个线程对该变量+1,一个线程对该变量-1, 实现交替5轮

package TreadTest1;
/**
 * 现在有两个线程,可以操作初始值为0的数,实现一个线程对该变量+1,一个线程对该变量 - 1, 实现交替5轮
 *
 * @author 77585211 线程 操作 资料类
 */
class MyThread01 {
      public int number = 0;
      // 两个方法, +1 ,-1
      public synchronized void increment() throws InterruptedException {
           // 判断
           // if(number!=0)会出现虚假判断
           while ( number != 0) {
               this .wait();
          }
           // 干活
          ++ number ;
          System. out .println(Thread. currentThread ().getName() + "\t" + number );
           // 释放
           this .notifyAll();
     }
      public synchronized void decrement() throws InterruptedException {
           // 判断
           // if(number!=0)会出现虚假判断
           while ( number == 0) {
               this .wait();
          }
           // 干活
          -- number ;
          System. out .println(Thread. currentThread ().getName() + "\t" + number );
           // 释放
           this .notifyAll();
     }
}
public class Test4 {
      public static void main(String[] args ){
          MyThread01 myThread01 = new MyThread01();
           new Thread(()->{
              
               try {
                    for ( int i = 1; i <=5; i ++) {
                         myThread01 .increment();
                        
                   }
                   
              } catch (Exception e ) {
                   
                    e .printStackTrace();
              }
              
          }, "AA" ).start();
          
           new Thread(()->{
              
               try {
                    for ( int i = 1; i <=5; i ++) {
                         myThread01 .decrement();
                        
                   }
              } catch (Exception e ) {
                   
                    e .printStackTrace();
              }
              
              
          }, "BB" ).start();
       new Thread(()->{
              
               try {
                    for ( int i = 1; i <=5; i ++) {
                         myThread01 .increment();
                        
                   }
              } catch (Exception e ) {
                   
                    e .printStackTrace();
              }
              
              
          }, "CC" ).start();
       new Thread(()->{
              
               try {
                    for ( int i = 1; i <=5; i ++) {
                         myThread01 .decrement();
                        
                   }
              } catch (Exception e ) {
                   
                    e .printStackTrace();
              }
              
              
          }, "DD" ).start();
          
     }
}
优化: 使用JUC 的锁 Condition接口


package TreadTest1;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
/**
 * 现在有两个线程,可以操作初始值为0的数,实现一个线程对该变量+1,一个线程对该变量 - 1, 实现交替5轮 使用ReentrantLock的方法
 *
 * @author 77585211
 *
 */
class MyThread02 {
      private int number = 0;
      private ReentrantLock lock = new ReentrantLock();
      private Condition condition = lock .newCondition();
      public void increment() throws InterruptedException {
           lock .lock(); // 线程一个一个的进
           try {
               while ( number != 0) {
                    condition .await();
              }
               // 干活
              ++ number ;
               System. out .println(Thread. currentThread ().getName() + "\t" + number );
               // 唤醒
               condition .signalAll();
          } finally {
               lock .unlock();
          }
     }
      public void decrement() throws InterruptedException {
           lock .lock(); // 线程一个一个的进
           try {
               while ( number == 0) {
                    condition .await();
              }
               // 干活
              -- number ;
               System. out .println(Thread. currentThread ().getName() + "\t" + number );
               // 唤醒
               condition .signalAll();
          } finally {
               lock .unlock();
          }
     }
     
     
     
}
public class Test5 {
      public static void main(String[] args ){
          MyThread02 thread02 = new MyThread02();
           new Thread(()->{
              
               try {
                    for ( int i = 1; i <=10; i ++) {
                        
                         thread02 .increment();
                   }
              } catch (Exception e ) {
                   
                    e .printStackTrace();
              }
              
              
          }, "AA" ).start();
          new Thread(()->{
              
               try {
                    for ( int i = 1; i <=10; i ++) {
                        
                         thread02 .decrement();
                   }
              } catch (Exception e ) {
                   
                    e .printStackTrace();
              }
              
              
          }, "BB" ).start();
          new Thread(()->{
              
               try {
                    for ( int i = 1; i <=10; i ++) {
                        
                         thread02 .increment();
                   }
              } catch (Exception e ) {
                   
                    e .printStackTrace();
              }
              
              
          }, "CC" ).start();
          
          new Thread(()->{
              
               try {
                    for ( int i = 1; i <=10; i ++) {
                        
                         thread02 .decrement();
                   }
              } catch (Exception e ) {
                   
                    e .printStackTrace();
              }
              
              
          }, "DD" ).start();
     }
}

重点:多线程的锁
1.都是同步方法,一个对象实例的时候
package TreadTest1;
import java.util.concurrent.TimeUnit;
class Phone{
     
      public synchronized void getIphone() throws InterruptedException{
          
          TimeUnit. SECONDS .sleep(3);
          System. out .println( "---------iphone" );
     }
     
      public synchronized void getAndroid(){
          System. out .println( "---------Android" );
          
          
     }
     
}
/**
 * 1.两个同步方法,一个对象的时候 ----------
 *
 *
 *
 *
 * @author 77585211
 *
 */
  public class Test6 {
   public static void main(String[]  args ){
     Phone phone = new Phone();
     
      new Thread(()->{
          
           try {
               phone .getIphone();
          } catch (Exception e ) {
          
               e .printStackTrace();
          }
          
     }, "AA" ).start();
    new Thread(()->{
          
           phone .getAndroid();
          
     }, "BB" ).start();
  }
}

结果:
---------iphone
---------Android

原因:
如果一个类中有多个 synchronized(), 只要有一个线程进入了一个 synchronized方法,其他线程都要等待。 因为synchronized是锁整个this.Object,被锁定后,其他线程不能进入 synchronized方法

2. 两个同步方法,两个对象的时候


package TreadTest1;
import java.util.concurrent.TimeUnit;
class Phone{
     
      public synchronized void getIphone() throws InterruptedException{
          
          TimeUnit. SECONDS .sleep(3);
          System. out .println( "---------iphone" );
     }
     
      public synchronized void getAndroid(){
          System. out .println( "---------Android" );
          
          
     }
     
}
/**
 * 1.两个同步方法,一个对象的时候 ---------- --------- iphone --------- Android
 * 2.两个同步方法,两个对象的时候 ---------- --------- Android --------- iphone
 *
 *
 *
 * @author 77585211
 *
 */
  public class Test6 {
   public static void main(String[]  args ){
     Phone phone1 = new Phone();
     Phone phone2 = new Phone();
     
      new Thread(()->{
          
           try {
               phone1 .getIphone();
          } catch (Exception e ) {
          
               e .printStackTrace();
          }
          
     }, "AA" ).start();
    new Thread(()->{
          
           phone2 .getAndroid();
          
     }, "BB" ).start();
  }
}
结果: --------- Android --------- iphone
结论:synchronized只会锁this.object。 不会影响其他的对象实例
3. 两个同步方法,一个普通方法,一个对象
package TreadTest1;
import java.util.concurrent.TimeUnit;
class Phone{
     
      public synchronized void getIphone() throws InterruptedException{
          
          TimeUnit. SECONDS .sleep(3);
          System. out .println( "---------iphone" );
     }
     
      public synchronized void getAndroid(){
          System. out .println( "---------Android" );
     }
      public void sayHello(){
          
          System. out .println( "--------hello" );
          
     }
     
}
/**
 * 1.两个同步方法,一个对象的时候 ---------- --------- iphone --------- Android
 * 2.两个同步方法,两个对象的时候 ---------- --------- Android --------- iphone
 * 3.两个同步方法,一个普通方法,一个对象 -->---- hello ----- iphone ----- Android
 *
 *
 * @author 77585211
 *
 */
  public class Test6 {
   public static void main(String[]  args ){
     Phone phone1 = new Phone();
     Phone phone2 = new Phone();
     
      new Thread(()->{
          
           try {
               phone1 .getIphone();
          } catch (Exception e ) {
          
               e .printStackTrace();
          }
          
     }, "AA" ).start();
    new Thread(()->{
          
           phone1 .getAndroid();
          
     }, "BB" ).start();
  new Thread(()->{
          
           phone1 .sayHello();
          
     }, "CC" ).start();
  }
}

结论:
--------hello
---------iphone
---------Android

3.结论  没有同步锁的方法不会被锁住,只有加了synchronized的方法才能锁住当前线程。


4. 两个静态同步方法,一个对象
package TreadTest1;
import java.util.concurrent.TimeUnit;
class Phone{
     
      public static   synchronized void getIphone() throws InterruptedException{
          
          TimeUnit. SECONDS .sleep(3);
          System. out .println( "---------iphone" );
     }
     
      public static synchronized void getAndroid(){
          System. out .println( "---------Android" );
     }
      public void sayHello(){
          
          System. out .println( "--------hello" );
          
     }
     
}
/**
 * 1.两个同步方法,一个对象的时候 ---------- --------- iphone --------- Android
 * 2.两个同步方法,两个对象的时候 ---------- --------- Android --------- iphone
 * 3.两个同步方法,一个普通方法,一个对象 -->---- hello ----- iphone ----- Android
 * 4.两个静态同步方法,一个对象 ---- --------- iphone --------- Android
 *
 * @author 77585211
 *
 */
  public class Test6 {
   public static void main(String[]  args ){
     Phone phone1 = new Phone();
     Phone phone2 = new Phone();
     
      new Thread(()->{
          
           try {
               phone1 . getIphone () ;
          } catch (Exception e ) {
          
               e .printStackTrace();
          }
          
     }, "AA" ).start();
    new Thread(()->{
          
           phone1 . getAndroid () ;
          
     }, "BB" ).start();
 
  }
}
结果:
---------iphone
---------Android
结论:所有静态同步方法用的锁是:类对象本身。

5. 两个静态同步方法,两个对象
package TreadTest1;
import java.util.concurrent.TimeUnit;
class Phone{
     
      public static   synchronized void getIphone() throws InterruptedException{
          
          TimeUnit. SECONDS .sleep(3);
          System. out .println( "---------iphone" );
     }
     
      public static   synchronized void getAndroid(){
          System. out .println( "---------Android" );
     }
      public void sayHello(){
          
          System. out .println( "--------hello" );
          
     }
     
}
/**
 * 1.两个同步方法,一个对象的时候 ---------- --------- iphone --------- Android
 * 2.两个同步方法,两个对象的时候 ---------- --------- Android --------- iphone
 * 3.两个同步方法,一个普通方法,一个对象 -->---- hello ----- iphone ----- Android
 * 4.两个静态同步方法,一个对象 ---- --------- iphone --------- Android
 * 5.两个静态同步方法,两个对象 --- --------- iphone --------- Android
 * @author 77585211
 *
 */
  public class Test6 {
   public static void main(String[]  args ){
     Phone phone1 = new Phone();
     Phone phone2 = new Phone();
     
      new Thread(()->{
          
           try {
               phone1 . getIphone () ;
          } catch (Exception e ) {
          
               e .printStackTrace();
          }
          
     }, "AA" ).start();
    new Thread(()->{
          
           phone2 . getAndroid () ;
          
     }, "BB" ).start();
 
  }
}

结果:
---------iphone
---------Android
结论: 静态同步方法不管是多少个对象实例,只要是一个类对象,当一个静态同步方法获取锁后,其他的静态同步方法必须等待。
6. 一个静态同步方法,一个非静态同步方法,一个对象
package TreadTest1;
import java.util.concurrent.TimeUnit;
class Phone{
     
      public static   synchronized void getIphone() throws InterruptedException{
          
          TimeUnit. SECONDS .sleep(3);
          System. out .println( "---------iphone" );
     }
     
      public synchronized void getAndroid(){
          System. out .println( "---------Android" );
     }
      public void sayHello(){
          
          System. out .println( "--------hello" );
          
     }
     
}
/**
 * 1.两个同步方法,一个对象的时候 ---------- --------- iphone --------- Android
 * 2.两个同步方法,两个对象的时候 ---------- --------- Android --------- iphone
 * 3.两个同步方法,一个普通方法,一个对象 -->---- hello ----- iphone ----- Android
 * 4.两个静态同步方法,一个对象 ---- --------- iphone --------- Android
 * 5.两个静态同步方法,两个对象 --- --------- iphone --------- Android
 * 6.一个静态同步方法,一个非静态同步方法,一个对象 --------- Android --------- iphone
 * @author 77585211
 *
 */
  public class Test6 {
   public static void main(String[]  args ){
     Phone phone1 = new Phone();
     Phone phone2 = new Phone();
     
      new Thread(()->{
          
           try {
               phone1 . getIphone () ;
          } catch (Exception e ) {
          
               e .printStackTrace();
          }
          
     }, "AA" ).start();
    new Thread(()->{
          
           phone1 .getAndroid();
          
     }, "BB" ).start();
 
  }
}

结果:
--------- Android -
-------- iphone
结论:静态同步方法锁住的是类对象,而非静态同步方法锁住的是当前对象实例。锁住的不是一个对象,所以syn的没有sleep的先被打印出来。
7: 一个静态同步方法,一个非静态同步方法,二个对象  
结果:
---------Android
---------iphone
结论:与6相同


创建多线程的方法4:线程池
题: 银行窗口办理业务      5个窗口    15个人办理业务  
package TreadTest1;
import java.util.Random;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
/**
* 根据线程池创建多线程
* @author 77585211
*
*银行窗口办理业务      5个窗口    15个人办理业务
*利用线程池
*/
public class Test3 {
    public static void main(String[] args) throws InterruptedException, ExecutionException{
        //实现2秒钟一个,时间调度
         ScheduledExecutorService service = Executors.newScheduledThreadPool(5);//5个线程池
        ScheduledFuture<Integer>  schedule =null;
        //15个人办理业务
        try {
            for (int i = 1; i <=15; i++) {
        
                     schedule = service.schedule(()->{
                        
                        //打印一下当前线程的名字
                        System.out.print(Thread.currentThread().getName());
                        //返回一个随机数
                        return new Random().nextInt(30);
                        
                        
                    }, 2, TimeUnit.SECONDS);
            
                     System.out.println("-------rerult:"+schedule.get());
                
                
            }
            
            
        } finally{
            service.shutdown();
            
        }
    
        
        
    
        
    }
    
public static void getExecuor() throws Exception{
    //5个窗口
    //ExecutorService service = Executors.newFixedThreadPool(5);
    //ExecutorService service = Executors.newSingleThreadExecutor();一个线程
    ExecutorService service = Executors.newCachedThreadPool();//随机的线程池
    Future<Integer> result=null;
        //15个人办理业务
        try {
            for (int i = 1; i <=15; i++) {
                result = (Future<Integer>) service.submit(()->{
                    
                    //打印一下当前线程的名字
                    System.out.print(Thread.currentThread().getName());
                    //返回一个随机数
                    return new Random().nextInt(30);
                    
                    
                });
                //打印随机数
                System.out.println("----result:"+result.get());
            }
            
            
        } finally{
            service.shutdown();
            
        }
    
}
}



总结:当窗口固定,且要重复提交业务的时候,用线程池







  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值