java中的thread_java中Thread的深入了解(三)

1.volatile

可以强制去掉缓存区 每次都去从内存读值

static byte value=0;

static boolean finish=false;

public static void testVolatile() throws InterruptedException {

value=0;

finish=false;

new Thread(new Runnable() {

@Override

public void run() {

while(value==0&&!finish);

console.info

("value is "+value+" finish is "+finish);

}

}).start();

Thread.sleep(1000);

new Thread(new Runnable() {

@Override

public void run() {

value=10;

finish=true;

console.info

("has set the finish");

}

}).start();

}

可以看到运行结果如图:第一个线程并没有如期结束,在线程循环里, 如果没有与其他线程产生交互 ,他不会读取内存的值 会始终使用缓存的值,所以第一个线程的死循环。

4493fc81786f

结果

这是因为cpu和线程有个缓存区,当线程运行的时候 读入需要的变量进入缓冲区

4493fc81786f

线程运行

所以我们可以通过volatile关键字 保证每次读取都会从实际内存里读取

4493fc81786f

volatile字段添加位置

2.concurrent的BlockingQueue

java 1.6之后有的这个接口,这个是一个线程安全的对象,用于线程之间的通信。

BlockingQueue是一个线程安全的队列接口 ,提供了 put take poll等方法

实现类有 ArrayBlockingQueue LinkedBlockingQueue PriorityBlockingQueue。

ArrayBlockingQueue初始化的时候要指定大小,且容量就是初始化指定的

LinkedBlockingQueue 是链表实现 不需要指定大小 会自动扩容

PriorityBlockingQueue 是一个有优先级的队列,可以让优先级高的先处理,优先级低的后处理

生产者 消费者 用这个就很好解决,如图:

4493fc81786f

生产者和消费者

4493fc81786f

BlockingQueue中线程运行

2.1LinkedBlockingQueue

public static void blockingQueueTest(){

BlockingQueue blockingDeque=new LinkedBlockingQueue();

new Thread(new Runnable() {

@Override

public void run() {

try {

console.info

(blockingDeque.take());

} catch (InterruptedException e) {

e.printStackTrace();

}

}

},"消费者").start();

new Thread(new Runnable() {

@Override

public void run() {

try {

blockingDeque.put("new Msg");

} catch (InterruptedException e) {

e.printStackTrace();

}

}

},"生产者").start();

}

2.2PriorityBlockingQueue (优先级)

public static class Message implements Comparable{

public String name;

public int value=0;

public Message(int value,String name) {

this.value = value;

this.name=name;

}

@Override

public int compareTo(Message o) {

return value-o.value;

}

}

public static void blockingQueueTests(){

PriorityBlockingQueue blockingDeque=new PriorityBlockingQueue ();

new Thread(new Runnable() {

@Override

public void run() {

for(int i=0;i<100;i++) {

try {

console.info

(blockingDeque.take().name);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

},"消费者").start();

new Thread(new Runnable() {

@Override

public void run() {

blockingDeque.put(new Message(100,"zhangsan"));

blockingDeque.put(new Message(0,"lisi"));

blockingDeque.put(new Message(0,"wangwu"));

blockingDeque.put(new Message(100,"zhaosi"));

}

},"生产者").start();

}

可以看put方法是阻塞的 直到里面有足够的空间存储,take也是阻塞的直到有内容的时候返回,所以上面的线程 即是是消费者直接运行 生产者后运行 也能正确的指向。

3.concurren包的线程池

Executors.newScheduledThreadPool 创建固定大小的线程池

Executors.newFixedThreadPool 创建固定大小的线程池

Executors.newCachedThreadPool 创建缓存线程池 从0 开始 每个线程存货一分钟

Executors.newSingleThreadExecutor 创建只有一个线程的线程池

实际上都是创建了一个ThreadPoolExecutor 控制了不同参数

/**

*

* corePoolSize 线程池最小保持线程数 即是他们处于空闲状态

* maximumPoolSize 线程池最大线程数

* keepAliveTime 如果线程数超出最小保持 那么线程最大空闲存活实际

* unit 存活时间单位单位

* 初始工作的缓冲区

*/

public ThreadPoolExecutor(int corePoolSize,

int maximumPoolSize,

long keepAliveTime,

TimeUnit unit,

BlockingQueue workQueue) {

}

eg:

public static void CountDownLatchTest() throws InterruptedException {

long startTime=System.currentTimeMillis();

CountDownLatch countDownLatch=new CountDownLatch(65535);

ScheduledExecutorService service = Executors.newScheduledThreadPool(9000);

for(int i=0;i<65535;i++){

service.execute(new Runnable() {

@Override

public void run() {

try {

Thread.sleep(200);

countDownLatch.countDown();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

});

}

try {

countDownLatch.await();

service.shutdown();

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println("所有线程完成了!"+(System.currentTimeMillis()-startTime)+"ms");

}

4.ReentrantReadWriteLock

synchronized 获取锁的方式 是不区分读写的,只要获取锁就排斥其他所有线程

ReentrantReadWriteLock 把锁分成读锁和写锁:读锁不排斥读锁 也就是多个线程都可以进入读锁。

写锁 排斥读锁和其它写锁,换成写锁的话只有一个线程能获取到锁。

锁用完需要进行释放unlock()

public static void ReadWriteLock(){

ReadWriteLock reentrantLock=new ReentrantReadWriteLock();

Lock readLock=reentrantLock.readLock();

Lock writeLock=reentrantLock.writeLock();

for(int i=0;i<2;i++)

new Thread(new Runnable() {

@Override

public void run() {

readLock.lock();

console.info

("获取到了读锁1");

try {

Thread.sleep(20);

readLock.unlock();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}).start();

for(int i=0;i<2;i++)

new Thread(new Runnable() {

@Override

public void run() {

writeLock.lock();

console.info

("获取到了写锁2");

try {

Thread.sleep(2000);

writeLock.unlock();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}).start();

}

会发现不是立马两个线程都运行了,是先运行了第一个,等待线程运行完成,在运行第二个。

4493fc81786f

运行结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值