预备知识:
1、AtomicInteger
这个类真的非常实用,更重要的是 它确实非常简单:
附上自己的代码,可以自己试试:
AtomicInteger,一个提供原子操作的Integer的类。在Java语言中,++i和i++操作并不是线程安全的,在使用的时候,不可避免的会用到synchronized关键字。而AtomicInteger则通过一种线程安全的加减操作接口。
代码:
package test;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 来看AtomicInteger提供的接口。
//获取当前的值
public final int get()
//取当前的值,并设置新的值
public final int getAndSet(int newValue)
//获取当前的值,并自增
public final int getAndIncrement()
//获取当前的值,并自减
public final int getAndDecrement()
//获取当前的值,并加上预期的值
public final int getAndAdd(int delta)
* @author YangBaoBao
*
*/
public class AtomicIntegerDemo {
public static void main(String[] args) {
AtomicInteger ai=new AtomicInteger(0);
int i1=ai.get();
v(i1);
int i2=ai.getAndSet(5);
v(i2);
int i3=ai.get();
v(i3);
int i4=ai.getAndIncrement();
v(i4);
v(ai.get());
}
static void v(int i)
{
System.out.println("i : "+i);
}
}
2 ReentrantReadWriteLock读写锁的使用
Lock比传统线程模型中的synchronized方式更加面向对象,与生活中的锁类似,锁本身也应该是一个对象。两个线程执行的代码片段要实现同步互斥的效果,它们必须用同一个Lock对象。
读写锁:分为读锁和写锁,多个读锁不互斥,读锁与写锁互斥,这是由jvm自己控制的,你只要上好相应的锁即可。如果你的代码只读数据,可以很多人同时读,但不能同时写,那就上读锁;如果你的代码修改数据,只能有一个人在写,且不能同时读取,那就上写锁。总之,读的时候上读锁,写的时候上写锁!
ReentrantReadWriteLock会使用两把锁来解决问题,一个读锁,一个写锁
线程进入读锁的前提条件:
没有其他线程的写锁,
没有写请求或者有写请求,但调用线程和持有锁的线程是同一个
线程进入写锁的前提条件:
没有其他线程的读锁
没有其他线程的写锁
到ReentrantReadWriteLock,首先要做的是与ReentrantLock划清界限。它和后者都是单独的实现,彼此之间没有继承或实现的关系。然后就是总结这个锁机制的特性了:
(a).重入方面其内部的WriteLock可以获取ReadLock,但是反过来ReadLock想要获得WriteLock则永远都不要想。
(b).WriteLock可以降级为ReadLock,顺序是:先获得WriteLock再获得ReadLock,然后释放WriteLock,这时候线程将保持Readlock的持有。反过来ReadLock想要升级为WriteLock则不可能,为什么?参看(a),呵呵.
(c).ReadLock可以被多个线程持有并且在作用时排斥任何的WriteLock,而WriteLock则是完全的互斥。这一特性最为重要,因为对于高读取频率而相对较低写入的数据结构,使用此类锁同步机制则可以提高并发量。
(d).不管是ReadLock还是WriteLock都支持Interrupt,语义与ReentrantLock一致。
(e).WriteLock支持Condition并且与ReentrantLock语义一致,而ReadLock则不能使用Condition,否则抛出UnsupportedOperationException异常。
下面看一个读写锁的例子:
1 package com.thread; 2 3 import java.util.Random; 4 import java.util.concurrent.locks.ReentrantReadWriteLock; 5 6 public class ReadWriteLockTest { 7 public static void main(String[] args) { 8 final Queue3 q3 = new Queue3(); 9 for(int i=0;i<3;i++) 10 { 11 new Thread(){ 12 public void run(){ 13 while(true){ 14 q3.get(); 15 } 16 } 17 18 }.start(); 19 } 20 for(int i=0;i<3;i++) 21 { 22 new Thread(){ 23 public void run(){ 24 while(true){ 25 q3.put(new Random().nextInt(10000)); 26 } 27 } 28 29 }.start(); 30 } 31 } 32 } 33 34 class Queue3{ 35 private Object data = null;//共享数据,只能有一个线程能写该数据,但可以有多个线程同时读该数据。 36 private ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); 37 public void get(){ 38 rwl.readLock().lock();//上读锁,其他线程只能读不能写 39 System.out.println(Thread.currentThread().getName() + " be ready to read data!"); 40 try { 41 Thread.sleep((long)(Math.random()*1000)); 42 } catch (InterruptedException e) { 43 e.printStackTrace(); 44 } 45 System.out.println(Thread.currentThread().getName() + "have read data :" + data); 46 rwl.readLock().unlock(); //释放读锁,最好放在finnaly里面 47 } 48 49 public void put(Object data){ 50 51 rwl.writeLock().lock();//上写锁,不允许其他线程读也不允许写 52 System.out.println(Thread.currentThread().getName() + " be ready to write data!"); 53 try { 54 Thread.sleep((long)(Math.random()*1000)); 55 } catch (InterruptedException e) { 56 e.printStackTrace(); 57 } 58 this.data = data; 59 System.out.println(Thread.currentThread().getName() + " have write data: " + data); 60 61 rwl.writeLock().unlock();//释放写锁 62 } 63 }
Thread-0 be ready to read data! Thread-1 be ready to read data! Thread-2 be ready to read data! Thread-0have read data :null Thread-2have read data :null Thread-1have read data :null Thread-5 be ready to write data! Thread-5 have write data: 6934 Thread-5 be ready to write data! Thread-5 have write data: 8987 Thread-5 be ready to write data! Thread-5 have write data: 8496
下面使用读写锁模拟一个缓存器:
1 package com.thread; 2 3 import java.util.HashMap; 4 import java.util.Map; 5 import java.util.concurrent.locks.ReadWriteLock; 6 import java.util.concurrent.locks.ReentrantReadWriteLock; 7 8 public class CacheDemo { 9 private Map<String, Object> map = new HashMap<String, Object>();//缓存器 10 private ReadWriteLock rwl = new ReentrantReadWriteLock(); 11 public static void main(String[] args) { 12 13 } 14 public Object get(String id){ 15 Object value = null; 16 rwl.readLock().lock();//首先开启读锁,从缓存中去取 17 try{ 18 value = map.get(id); 19 if(value == null){ //如果缓存中没有释放读锁,上写锁 20 rwl.readLock().unlock(); 21 rwl.writeLock().lock(); 22 try{ 23 if(value == null){ 24 value = "aaa"; //此时可以去数据库中查找,这里简单的模拟一下 25 } 26 }finally{ 27 rwl.writeLock().unlock(); //释放写锁 28 } 29 rwl.readLock().lock(); //然后再上读锁 30 } 31 }finally{ 32 rwl.readLock().unlock(); //最后释放读锁 33 } 34 return value; 35 } 36 37 }
3、
Thread的setDaemon(true)方法的作用
定义:守护线程--也称“服务线程”,在没有用户线程可服务时会自动离开。优先级:守护线程的优先级比较低,用于为系统中的其它对象和线程提供服务。
设置:通过setDaemon(true)来设置线程为“守护线程”;将一个用户线程设置为守护线程的方式是在 线程对象创建 之前 用线程对象的setDaemon方法。
example: 垃圾回收线程就是一个经典的守护线程,当我们的程序中不再有任何运行的Thread,程序就不会再产生垃圾,垃圾回收器也就无事可做,所以当垃圾回收线程是JVM上仅剩的线程时,垃圾回收线程会自动离开。它始终在低级别的状态中运行,用于实时监控和管理系统中的可回收资源。
生命周期:守护进程(Daemon)是运行在后台的一种特殊进程。它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。也就是说守护线程不依赖于终端,但是依赖于系统,与系统“同生共死”。那Java的守护线程是什么样子的呢。当JVM中所有的线程都是守护线程的时候,JVM就可以退出了;如果还有一个或以上的非守护线程则JVM不会退出。
例子程序:
thread = new Thread(this);
thread.setDaemon(true);
thread.start();
当java虚拟机中没有非守护线程在运行的时候,java虚拟机会关闭。当所有常规线程运行完毕以后,守护线程不管运行到哪里,虚拟机都会退出运行。所以你的守护线程最好不要写一些会影响程序的业务逻辑。否则无法预料程序到底 会出现什么问题。
import java.io.IOException;
/*
* 守护线程在没有用户线程可服务时自动离开
* 在Java中比较特殊的线程是被称为守护(Daemon)线程的低级别线程。
* 这个线程具有最低的优先级,用于为系统中的其它对象和线程提供服务。
* 将一个用户线程设置为守护线程的方式是在线程对象创建之前调用线程对象的setDaemon方法。
* 典型的守护线程例子是JVM中的系统资源自动回收线程,
* 我们所熟悉的Java垃圾回收线程就是一个典型的守护线程,
* 当我们的程序中不再有任何运行中的Thread,
* 程序就不会再产生垃圾,垃圾回收器也就无事可做,
* 所以当垃圾回收线程是Java虚拟机上仅剩的线程时,Java虚拟机会自动离开。
* 它始终在低级别的状态中运行,用于实时监控和管理系统中的可回收资源。
* 守护进程(Daemon)是运行在后台的一种特殊进程。它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。
* 也就是说守护线程不依赖于终端,但是依赖于系统,与系统“同生共死”。
* 那Java的守护线程是什么样子的呢。
* 当JVM中所有的线程都是守护线程的时候,JVM就可以退出了;
* 如果还有一个或以上的非守护线程则JVM不会退出。
*/
public class ThreadDemo extends Thread {
public ThreadDemo() {
super("zhuyong");
}
/** *//**
* 线程的run方法,它将和其他线程同时运行
*/
public void run(){
for(int i = 1; i <= 40; i++){
try{
Thread.sleep(100);
} catch (InterruptedException ex){
ex.printStackTrace();
}
System.out.println("TestThread: "+Thread.currentThread().getName() +i);
}
}
public static void main(String [] args){
ThreadDemo test = new ThreadDemo();
test.setDaemon(true);
test.start();
System.out.println("isDaemon = " + test.isDaemon());
try {
System.in.read(); // 接受输入,使程序在此停顿,一旦接收到用户输入,main线程结束,守护线程自动结束
} catch (IOException ex) {
ex.printStackTrace();
}
}
}