黑马程序员--------java提高-- 多线程

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

1 线程间的通信

  线程安全问题可以用银行转账来解释

    线程的互斥操作
   
   关于synchronized关键字

   calss Outputer
   {

      public synchronized void output()
       {


        }

         public static synchronized void output2()
       {


        }
    }
  问 output 和output2能同步吗?:不能 sattic锁住的是Outputer.class
                                      output锁住的是this(调用对象);


-------------------------
 线程间的同步
  子线程循环10次,接着主线程循环100次,子线程在循环10依次交替执行
循环50次

    
 wait 和notify实现线程间的通信
   
  经验:要用到共同数据(包括同步锁)的若干个方法应该归在同一个类身上。这种设计正好体现了

高类聚和健壮性。这样的好处,以后只要调用这个类的线程都是同步的,类内部天然石同步的。

  实现代码:
   
   class output
{
    boolean flag = false;//有产品
    
    public synchronized void sub()//消费者
    {
        if(!flag)
        {
            try {
                this.wait();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        for(int i=0;i<10;i++)
        {
            System.out.println("----sub----"+i);
        }
        flag = false;
        this.notify();
        
    }
    
    public synchronized void  main()//生产者
    {
        if(flag)
        {
            try {
                this.wait();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        for(int j=0;j<100;j++)
        {
            System.out.println("--main---"+j);
        }
        flag = true;
        this.notify();
    }
    

-----------------------------
public static void main(String[] args) {
        // TODO Auto-generated method stub
         output output = new output();
          
         new Thread(new Runnable() {
            
            @Override
            public void run() {
                // TODO Auto-generated method stub
                for(int i=0;i<50;i++)
                {
                    output.sub();
                }    
            }
        }).start();
        
        for(int k=0;k<50;k++)
        {
            output.main();
        }
    }


--------------------------------------------------

ThreadLocal 实现线程范围类的共享数据

 借助 Map 存储每个线程的数据。线程操作模块直接到Map中取数据。

保证不同线程间数据了安全性。


ThreadLocal 代表一个变量,故每次只能存放一个数据,当有多个数据时
需定义多个ThreadLocal对象,也可将数据封装到一个类对象上用一个TreadLocal存储

使用ThreadLocal的好处:当线程结束时,会自动释放该线程关联的数据。


-------------------------------------
多个线程共享数据的方式探讨

买票例子


1 让资源提供对外访问的方法

2 让这些方法互斥

    class Product//拉煤优化进程间通信 优化代码
{
    private String name;
    private int num = 0;
    private boolean flag = false;
    public Product(String name)
    {
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getNum() {
        return num;
    }
    public void setNum(int num) {
        this.num = num;
    }
    
    //生产行为
    public void put()
    {
        while(true)
        {
            synchronized(this)
            {
                while(this.flag)
                {
                        try
                          {
                             this.wait();
                        
                          }catch(InterruptedException e)
                          {
                                  
                          }
                }
                System.out.println(name+"---"+"生产者----"+(++num));//模拟生产者进行的操作处理
                flag = true;
                this.notifyAll();//唤醒消费者
            }
        }
    }
    //消费行为
    public  void get()
    {
        while(true)
        {
            synchronized(this)
            {
                while(flag == false)
                {
                    try{this.wait();}catch(InterruptedException e){};
                }
                System.out.println(name+"---"+"消费者--------------"+num);
                flag = false;
                this.notifyAll();//唤醒生产者
            }
        }
    }
}

------------------------------------------
3 资源传递给Runnable 对象

4 在runnable对象的run方法中调用资源提供的方法


class Producer implements Runnable
{
    private Product product;
    public Producer(Product product)//接收资源
    {
        this.product = product;
    }
    public void run()
    {
        product.put();//调用资源的方法
    }
    
}
//消费者
class Consumer implements Runnable
{
    private Product product;
    public Consumer(Product product)
    {
        this.product = product;
    }
    public void run()
    {
        product.get();
    }
    
}

-----------------------------------------------------------
JDK 5 下的线程新特性

1 java5中的线程并发库:java.util.concurrent

   原子性操作类的应用

   AtomicInteger();
   AtomicIntegerArray();
   .
   .
   .
   AtomicXXXX

   对正数操作时能对其他线程进行互斥操作。


2 线程池

   一概念:线程,循环到池子类拿任务,拿到就执行,没拿到就等待。如此周而复始的持续运行

   二Excutors类的使用
    
      1 如何创建线程池?
       
       Executors.newXXX的方式创建//返回值为:ExecutorService

       如:ExecutorService  services = Executors.newFixedThreadPool(3);// 创建一个线程池里面有三个线程。
 
      2 如何往池里添加任务?
          services.execute(new Runnable(){ public run(){业务代码}});
          services.submit();
         // 线程池中的某个线程会去执行

      3 如何关闭线程池:servicces.shutdown();//没任务时关闭
                       services.shutdownNow();//立即关闭线程

      4 线程池的分类:
        1 固定的线程池:Executors.newFixedThreadPool(int);
        2 缓存的线程池:Executors.newCachedThreadPool();//线程池中的线程数是动态的

        3 单个线程:Executors.newSingleThreadExcutor();//始终保持有一个线程在那里运行,如果线程死了,会自动找个新的线程继续运行。(如何实现现线程死了后重新启动?)

        4 定时器线程池
           Executors.newScheduledThreadPool(3).schedule(new Runnable(){ run(){}},
                                                         10,
                                                         TimeUnit.SECONDS;
                                                         
                                                        )
          

           可获得多种调度模式:如没过多时间调用一次等等.


 ------------------------------------------------------------
      Callable 和 Future;// 当一个线程运行完和获得线程返回的值

     Callable 类型的任务可以返回结果,返回结果用Futuer去接收。
     注意:Callablel类型的任务提交到线程池的方式:submit();

   
-------------------------------------------


Lock

读写锁:分为读锁,和写锁。多个读锁不互斥,读锁与写锁互斥
写锁与写锁互斥。这是JVM自己控制的。只要你上好锁就可以。
如果代码只读数据,可以很多人同时读(不互斥),但不能同时写,那就上读锁
如果你的代码修改数据只能有一个人在写且不能同时读取,那就上写锁。


Condition:
参见 javalearn7


-------------------------------------
Semaphore 实现信号灯

相当于有多个锁,当有所被释放,就能允许新的线程进入


------------------------
其他同步工具类
CycllBarrier

表示大家彼此等待,大家集合好后才开始出发,分散活动之后又在指定的地点集合


CycllBarrier的await()方法

-------
CountDownLatch
  犹如倒计时计数器,调用CountDownLatch对象的countDown方法就将计数器减一,当计数器到0时
则所有等待者或单个等待者开始执行。

-------
Exchanger
 
  用于两个线程之间交换数据,每个线程在完成一定的事务之后想和对方交换数据。
第一个先拿出数据的线程将一直等待第二线程拿着数据到来时,才能彼此交换数据

 不同线程调用同一个Exchanger的exchange(object)方法

-------------------------
可阻塞队列

 ArrayBlockingQueue
   只有put方法和take方法猜具有阻塞功能
 
-------------------
java5中提供的同步集合

hashSet
hashMap
arryList

在多个线程操作的时候会出现问题的

所有建议:ConcurrentHashMap代替hashmap或者加上同步的处理。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值