------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或者加上同步的处理。