1. 创建和启动线程的两种传统方式
概念:java 实现一条线索
有两种方法:
1、继承thread 类
例子:
// 继承Thread类
new Thread(){
publicvoid run(){
while(true){
try {
Thread.sleep(2000);
}catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
}
}
}.start();
2、实现runnable接口
例子:
//实现Runnable接口
new Thread(new Runnable(){
publicvoid run(){
while(true){
try {
Thread.sleep(2000);
}catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
}
}
}).start();
2.传统的定时器实现方式
代码
importjava.util.concurrent.Executors;
importjava.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
publicclass TimerTest {
/**
* 定时器
*/
publicstaticvoid main(String[] args) {
ScheduledExecutorServiceservice = Executors.newScheduledThreadPool(3);
service.scheduleAtFixedRate(
new Runnable(){
publicvoid run() {
System.out.println(Thread.currentThread().getName());
}
},
10,
1,
TimeUnit.SECONDS);
while(true){
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
}
}
}
3.传统的线程同步互斥
线程的同步和互斥
Synchronized
线程创建过程:同步:子线程循环10次,接着主线程循环100次,接着的又回到子线程循环10次,接着又回到主线程循环10次。如此,循环50次。
packageorg.nagi.Thread;
publicclass TeaTSynchronized {
static Businessbusiness =new Business();
publicstaticvoid main(String[] args)throws InterruptedException {
//子线程
TeaTSynchronized.init();
//主线程
for(int i=0;i<50;i++){
business.main();
}
}
//子线程
publicstaticvoid init(){
new Thread(new Runnable() {
@Override
publicvoid run() {
for(int i=0;i<50;i++){
try {
business.sub();
}catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
}
class Business{
booleanshouldSub =true;
//子线程方法
publicsynchronizedvoid sub()throws InterruptedException{
//使用我当前线程的,等待
while(!shouldSub){//这里使用while而不用iF防止假唤醒!详细信息可参考JavaApi
this.wait();
}
for(int i=0;i<10;i++){
System.out.println(Thread.currentThread().getName()+"count" + i);
}
shouldSub = false;
this.notify();
}
//主线程的操作方法
publicsynchronizedvoid main()throws InterruptedException{
while(shouldSub){//这里使用while而不用iF防止假唤醒!详细信息可参考JavaApi
//使用我当前线程的,等待
this.wait();
}
for(int i=0;i<100;i++){
System.out.println(Thread.currentThread().getName()+"count" + i);
}
shouldSub = true;
this.notify();
}
}
4.传统的线程间通讯
ThreadLoacal 线程间的通信:就是线程内的数据共享,两个或多个代码块共享的一个数据, 在代码块之间数据是独立,在代码块之内是数据共享的。
5.ThreadLocal与线程级变量共享
ThreadLoacal就相当Map; 一个线程TheadLoacal 只能放一个数据;
6.多线程访问共享数据的经典总结
1、可以把需要共享的数据转给runnable 接口;
2、将共享数据的封装为一个对象, 在多个线程里面runnable 接口run方法
3、可以使用ThreadLocal类
如果想要操作一个原子性的数据类型可以用原子方式更新的 int 值。
在操作某一个数据原子性操作的时候,可以使用AtomicInteger AtomicIntegerArray
定义一个线程池:
packageorg.nagi.Thread;
importjava.util.concurrent.ExecutorService;
importjava.util.concurrent.Executors;
/**
*线程池
*@author dell
*
*/
publicclass ThreadPool {
publicstaticvoid main(String[] args) {
/*缓存线程池*/
//ExecutorService threadcached=Executors.newCachedThreadPool();
/*单个线程池,当线程死了,自动会有线程启动*/
//ExecutorService threadSingle = Executors.newSingleThreadScheduledExecutor();
//线程池
ExecutorService threadPool = Executors.newFixedThreadPool(4);
threadPool.execute(new Runnable() {
@Override
publicvoid run() {
for(int i=0;i<5;i++){
System.out.println(Thread.currentThread().getName()+"任务:"+ i);
}
}
});
//当任务执行完成之后就可以关闭掉
threadPool.shutdown();
}
}
8.Java5中的定时器
方法参考
ScheduledFuture
schedule(Callable callable, long delay, TimeUnit unit)
创建并执行在给定延迟后启用的 ScheduledFuture。
ScheduledFuture
Executors.newScheduledThreadPool(4).scheduleAtFixedRate(
new Runnable() {
@Override
publicvoid run() {
System.out.println("Bombing");
}
},
4,//多少秒之后执行run方法
2,//间隔多少时间执行
TimeUnit.SECONDS);//时间单位
Callable和Futrue使用:
/*使用Callable调用回返一个数据,使用futrue去取并且可以指定时间*/
ExecutorService threadSingle = Executors.newSingleThreadExecutor();
Future<String> futrue =threadSingle.submit(newCallable<String>() {
@Override
public String call()throws Exception {
Thread.sleep(1000);
return"hello world";
}
});
try {
//futrue取出数据
System.out.println("result:" + futrue.get(3,TimeUnit.SECONDS));
} catch (Exceptione) {
e.printStackTrace();
}
9.java5提供的可返回结果的线程模式
10.java5中的锁与读写锁
Lock:java 中锁Lock 比Synchronized更加的面对对象,与生活中的对象一样,锁业是一个对象。
例子代码:
importjava.util.concurrent.ExecutorService;
importjava.util.concurrent.Executors;
importjava.util.concurrent.locks.Lock;
importjava.util.concurrent.locks.ReentrantLock;
publicclass LockTest {
/**
* @param args
*/
publicstaticvoid main(String[] args) {
final Business business =new Business();
ExecutorService service = Executors.newFixedThreadPool(3);
for(int i=0;i<3;i++){
service.execute(new Runnable(){
publicvoid run(){
business.service();
}
});
}
service.shutdown();
}
}
class Business{
privateintcount = 0;
Lock lock = new ReentrantLock();
publicvoid service(){
lock.lock();
count++;
try {
Thread.sleep(10);
System.out.println(count);
} catch (InterruptedException e) {
e.printStackTrace();
}finally{
lock.unlock();
}
}
}
Lock : 还可以实现一个读写锁,
/**
* 读的的时候不互斥
* 写的时候互斥
* @param key
* @return
*/
public Object getEntityFromCache(Stringkey){
Object object = cache.get(key);
if(object ==null){
lock.readLock().lock();//锁得read操作
try{
object ="btbu";//去数据库查找
cache.put(key, object);
}finally{
lock.readLock().unlock();
}
}
return object;
}
11.LockCondition同步工具
Condition 将 Object 监视器方法(wait、notify和notifyAll)分解成截然不同的对象,以便通过将这些对象与任意Lock 实现组合使用,为每个对象提供多个等待 set(wait-set)。其中,Lock 替代了 synchronized 方法和语句的使用,Condition 替代了 Object 监视器方法的使用。
例子:
packageorg.nagi.Thread;
import java.util.concurrent.locks.Condition;
importjava.util.concurrent.locks.ReentrantLock;
publicclass TestCondition {
static Businessbusiness =new Business();
publicstaticvoid main(String[] args)throws InterruptedException {
//子线程
TestCondition.init();
//主线程
for(int i=0;i<50;i++){
business.main();
}
}
//子线程
publicstaticvoid init(){
new Thread(new Runnable() {
@Override
publicvoid run() {
for(int i=0;i<50;i++){
try {
business.sub();
}catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
}
class Business{
booleanshouldSub =true;
ReentrantLock lock = new ReentrantLock();
Condition condition =lock.newCondition();
//子线程方法
public void sub()throws InterruptedException{
lock.lock();
try{
//使用我当前线程的,等待
while(!shouldSub){//这里使用while而不用iF防止假唤醒!详细信息可参考JavaApi
condition.await();
}
for(int i=0;i<10;i++){
System.out.println(Thread.currentThread().getName()+"count" + i);
}
shouldSub =false;
}finally{
condition.signal();
}
}
//主线程的操作方法
publicsynchronizedvoid main()throws InterruptedException{
lock.lock();
try{
while(shouldSub){//这里使用while而不用iF防止假唤醒!详细信息可参考JavaApi
//使用我当前线程的,等待
condition.await();
}
for(int i=0;i<100;i++){
System.out.println(Thread.currentThread().getName()+"count" + i);
}
shouldSub = true;
this.notify();
}finally{
condition.signal();
}
}
}
缓冲队列的实现
import java.util.concurrent.locks.Condition;
importjava.util.concurrent.locks.Lock;
importjava.util.concurrent.locks.ReentrantLock;
/**
*缓冲队列
*@author dell
*
*/
class BoundedBuffer{
final Locklock =new ReentrantLock();
final ConditionnotFull =lock.newCondition();
final ConditionnotEmpty =lock.newCondition();
//一个数组的缓存区
final Object[]items =new Object[100];
intputptr,takeptr,count;
//存放的操作
publicvoid put(Object x)throws InterruptedException {
lock.lock();
try {
while (count ==items.length)
notFull.await();
items[putptr] = x;
if (++putptr ==items.length)putptr = 0;
++count;
notEmpty.signal();
} finally {
lock.unlock();
}
}
//取出数据的操作
public Object take()throwsInterruptedException {
lock.lock();
try {
while (count == 0)
notEmpty.await();
Object x = items[takeptr];
if (++takeptr ==items.length)takeptr = 0;
--count;
notFull.signal();
return x;
} finally {
lock.unlock();
}
}
}
12.Semaphore同步工具
代码:
importjava.util.concurrent.ExecutorService;
importjava.util.concurrent.Executors;
importjava.util.concurrent.Semaphore;
/**
*信号灯
*@author dell
*
*/
publicclass SemaphoreTest {
publicstaticvoid main(String[] args) {
//缓存连接池
ExecutorService service = Executors.newCachedThreadPool();
final Semaphore sp =new Semaphore(3);
for(int i=0;i<10;i++){
Runnable runnable = new Runnable(){
publicvoid run(){
try {
sp.acquire();//获得信号量许可
}catch (InterruptedException e1) {
e1.printStackTrace();
}
System.out.println("线程" + Thread.currentThread().getName() +
"进入,当前已有" + (3-sp.availablePermits()) +"个并发");
try {
Thread.sleep((long)(Math.random()*10000));
}catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程" + Thread.currentThread().getName() +
"即将离开");
sp.release();//释放信号量
//下面代码有时候执行不准确,因为其没有和上面的代码合成原子单元
System.out.println("线程" + Thread.currentThread().getName() +
"已离开,当前已有" + (3-sp.availablePermits()) +"个并发");
}
};
//执行已提交的 Runnable任务的对象。
service.execute(runnable);
}
}
}
运行结果:
线程pool-1-thread-1进入,当前已有1个并发
线程pool-1-thread-1即将离开
线程pool-1-thread-1已离开,当前已有0个并发
线程pool-1-thread-2进入,当前已有1个并发
线程pool-1-thread-2即将离开
线程pool-1-thread-2已离开,当前已有0个并发
线程pool-1-thread-3进入,当前已有1个并发
线程pool-1-thread-3即将离开
13.CyclicBarrier同步工具
一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)。在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时 CyclicBarrier 很有用。因为该 barrier 在释放等待线程后可以重用,所以称它为循环的 barrier。
代码:
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
*并发工具辅佐类
*
*之循环障碍点
*@author dell
*
*/
publicclass CyclicBarrierTest {
publicstaticvoid main(String[] args) {
ExecutorService service = Executors.newCachedThreadPool();
final CyclicBarrier cb =newCyclicBarrier(3);
for(int i=0;i<3;i++){
Runnable runnable = new Runnable(){
publicvoid run(){
try {
Thread.sleep((long)(Math.random()*10000));
System.out.println("线程" + Thread.currentThread().getName() +
"即将到达集合地点1,当前已有" + cb.getNumberWaiting() +"个已经到达,正在等候");
cb.await();
Thread.sleep((long)(Math.random()*10000));
System.out.println("线程" + Thread.currentThread().getName() +
"即将到达集合地点2,当前已有" + cb.getNumberWaiting() +"个已经到达,正在等候");
cb.await();
Thread.sleep((long)(Math.random()*10000));
System.out.println("线程" + Thread.currentThread().getName() +
"即将到达集合地点3,当前已有" + cb.getNumberWaiting() +"个已经到达,正在等候");
cb.await();
}catch (Exception e) {
e.printStackTrace();
}
}
};
service.execute(runnable);
}
service.shutdown();
}
}
14.CountDownLatch同步工具
一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。首先先是点时器,
用给定的计数 初始化 CountDownLatch。由于调用了countDown()方法,所以在当前计数到达零之前,await方法会一直受阻塞。之后,会释放所有等待的线程,await的所有后续调用都将立即返回。这种现象只出现一次——计数无法被重置。
importjava.util.concurrent.CountDownLatch;
importjava.util.concurrent.ExecutorService;
importjava.util.concurrent.Executors;
/**
*程序计数器
*@author dell
*
*/
publicclass CountdownLatchTest {
publicstaticvoid main(String[] args) {
ExecutorService service = Executors.newCachedThreadPool();
//命令
final CountDownLatch cdOrder =new CountDownLatch(1);
//需要3个都为了时候再执行
final CountDownLatch cdAnswer =new CountDownLatch(3);
for(int i=0;i<3;i++){
Runnable runnable = new Runnable(){
publicvoid run(){
try {
System.out.println("线程" + Thread.currentThread().getName() +
"正准备接受命令");
cdOrder.await();
System.out.println("线程" + Thread.currentThread().getName() +
"已接受命令");
Thread.sleep((long)(Math.random()*10000));
System.out.println("线程" + Thread.currentThread().getName() +
"回应命令处理结果");
//减1,当计数器为0的时候,再可以往下执行
cdAnswer.countDown();
}catch (Exception e) {
e.printStackTrace();
}
}
};
service.execute(runnable);
}
try {
Thread.sleep((long)(Math.random()*10000));
System.out.println("线程" + Thread.currentThread().getName() +
"即将发布命令");
cdOrder.countDown();
System.out.println("线程" + Thread.currentThread().getName() +
"已发送命令,正在等待结果");
cdAnswer.await();
System.out.println("线程" + Thread.currentThread().getName() +
"已收到所有响应结果");
} catch (Exception e) {
e.printStackTrace();
}
service.shutdown();
}
}
15.Exchanger同步与数据交换工具
可以在对中对元素进行配对和交换的线程的同步点。每个线程将条目上的某个方法呈现给exchange方法,与伙伴线程进行匹配,并且在返回时接收其伙伴的对象。Exchanger 可能被视为SynchronousQueue 的双向形式。Exchanger 可能在应用程序(比如遗传算法和管道设计)中很有用。
importjava.util.concurrent.Exchanger;
importjava.util.concurrent.ExecutorService;
importjava.util.concurrent.Executors;
/**
*当两个现场都到达的时候,再可以实现线程的数据交换
*@author dell
*
*/
publicclass ExchangerTest {
publicstaticvoid main(String[] args) {
ExecutorService service = Executors.newCachedThreadPool();
finalExchanger exchanger =newExchanger();
service.execute(new Runnable(){
publicvoid run() {
try {
Thread.sleep((long)(Math.random()*10000));
String data1 ="zxx";
System.out.println("线程" + Thread.currentThread().getName() +
"正在把数据" + data1 +"换出去");
String data2 = (String)exchanger.exchange(data1);
System.out.println("线程" + Thread.currentThread().getName() +
"换回的数据为" + data2);
}catch(Exception e){
}
}
});
service.execute(new Runnable(){
publicvoid run() {
try {
Thread.sleep((long)(Math.random()*10000));
String data1 ="lhm";
System.out.println("线程" + Thread.currentThread().getName() +
"正在把数据" + data1 +"换出去");
String data2 = (String)exchanger.exchange(data1);
System.out.println("线程" + Thread.currentThread().getName() +
"换回的数据为" + data2);
}catch(Exception e){
}
}
});
}
}
16.Java5中的可阻塞队列
队列:先进先出
import java.util.concurrent.ArrayBlockingQueue;
importjava.util.concurrent.BlockingQueue;
importjava.util.concurrent.ExecutorService;
importjava.util.concurrent.Executors;
/**
*阻塞队列
*@author dell
*
*/
publicclass BlockingQueueCondition {
publicstaticvoid main(String[] args) {
ExecutorService service = Executors.newSingleThreadExecutor();
final Business3 business =new Business3();
service.execute(new Runnable(){
publicvoid run() {
for(int i=0;i<50;i++){
business.sub();
}
}
});
for(int i=0;i<50;i++){
business.main();
}
}
}
class Business3{
//队列
BlockingQueue subQueue =newArrayBlockingQueue(1);
BlockingQueue mainQueue =newArrayBlockingQueue(1);
{//匿名构造方法,有多少个对象就有多少匿名构造方法
try {
mainQueue.put(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
publicvoid sub(){
try
{
mainQueue.take();
for(int i=0;i<10;i++){
System.out.println(Thread.currentThread().getName()+" :" + i);
}
subQueue.put(1);
}catch(Exception e){
}
}
publicvoid main(){
try
{
subQueue.take();
for(int i=0;i<5;i++){
System.out.println(Thread.currentThread().getName()+" :" + i);
}
mainQueue.put(1);
}catch(Exception e){
}
}
}
17.传统与java5中的同步集合
1、在java5 之后并入了一个并发事务库
java.util.concurrent
在并发编程中很常用的实用工具类。
2、HashSet 是单列表的只有的一个Key,而HashMap 双列表一个key 和一个value,HashSet 是底层是使用HashMap ,只是不用Value的那一部分。
3、在迭代集合集合的时候不能对集合进行需要。