美文网首页
java中Thread的深入了解(二)

java中Thread的深入了解(二)

作者: Charon_Pluto | 来源:发表于2017-09-06 16:43 被阅读38次

一.synchronized方法和synchronized代码块

synchronized方法 只有一个线程能访问,只有这个方法执行完之后其他线程才能访问

synchronized方法的锁是当前对象,也就是如果new多次是不能阻止多个线程访问代码的

public classSyncTest {

/**

*对于SyncTest的对象 只有一个线程能访问

*对于不同的SyncTest的对象可以有多个线程访问

*/

public synchronized void say1(){

System.out.println("hello get the lock1!");

//休眠200s不释放锁

try{

Thread.sleep(200*1000);

}catch(InterruptedException e) {

e.printStackTrace();}

}

/**

* 与synchronized方法相同

*/

public void say2(){

synchronized(this){

System.out.println("hello get the lock2!");

try{

Thread.sleep(200*1000);

}catch(InterruptedException e) {

e.printStackTrace();}

}

}

/**

* 同一时间只有一个线程能访问

* 与synchronized方法不同,这样即使多次new也跟使用同一个对象是一样的 只有一个线程能访问

**/

public void say3(){

synchronized(SyncTest.class){

System.out.println("hello get the lock3!");

try{

Thread.sleep(200*1000);

}catch(InterruptedException e) {

e.printStackTrace();}

}

}

}

测试运行同步方法和同步代码块:

synchronized方法和synchronized代码块的三种测试

1.测试say1()方法发现刚开始时只打印了一段,而说明只有一个线程访问了。

测试say1()方法

2.同步方法默认是锁当前类对象,在多次new的时候,并不能起到锁方法的作用。

测试say1()方法

3.同步代码段可以锁类,这样即使多次new也跟使用同一个对象是一样的,只有一个线程能访问。

测试say3()方法

举例子:

最为线程安全类 最常见的做法就是加synchronized方法

StringBuilder 线程不安全

StringBuffer  线程安全:看StringBuffer源码,可以看见 所有方法都加了synchronized

HashMap线程不安全

HashTable 线程安全


二.Thread类常用方法

名称 new Thread(String name)   和 new Thread(Runnable run,String name)

获取当前: Thread Thread.current();

获取当前所有Thread的数量:Thread.activeCount();

eg:

测试结果

三.线程变量ThreadLocal

ThreadLocal是一个特殊的模板变量 每个线程获取到的都是自己的值,看源码就知道 其实是利用了Thread.currentThread(),然后利用了 map结构存储,所以ThreadLocal中的map map.get(Thread.currentThread()); 返回的就是不同的值。

public class ThreadLocalTest{    

private static ThreadLocal<ThreadLocalTest> threadLocal=new ThreadLocal<>();;

private static ThreadLocaTest mainThreadLocal;

/**

* 创建当前线程的ThreadLocal对象

*/

public static void prepare(){

if(threadLocal.get()==null){

threadLocal.set(new ThreadLocalTest());

}

}

public static void prepareMain(){

if(mainThreadLocal!=null){

throw new RuntimeException("只有一个线程可以调用prepareMain");

}

mainThreadLocal=new ThreadLocalTest();

if(threadLocal.get()==null){

threadLocal.set(mainThreadLocal);

}

}

public static ThreadLocalTest getMain(){

return mainThreadLocal;

}

public static ThreadLocalTest myThreadTest(){

return threadLocal.get();

}

private ThreadLocalTest(){

}

}

public static  voidshowThreadLocal(){

ThreadLocalTest.prepareMain();

new Thread(new Runnable() {

@Override

public void run() {

if(ThreadLocalTest.getMain()!=ThreadLocalTest.myThreadTest()){

console.info(Thread.currentThread().getName()+"当前不是主线程");

}else{

console.info(Thread.currentThread().getName()+"当前是主线程");

}

}

}).start();

if(ThreadLocalTest.getMain()!=ThreadLocalTest.myThreadTest()){

console.info(Thread.currentThread().getName()+"当前不是主线程");

}else{

console.info(Thread.currentThread().getName()+"当前是主线程");

}

}

输出结果

其实现原理 利用的是Thread.currentThread();

四.concurrent包的CountDownLatch

一个辅助类,初始化的时候指定数据个数,没调用一次countDown()数字减少一个。

一个方法 countDown() 一个方法await()。

public static void CountDownLatchTests() throws InterruptedException {

long startTime=System.currentTimeMillis();

CountDownLatch countDownLatch=new CountDownLatch(65535);

ThreadPool threadPool=new ThreadPool(10000);

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

 new Thread(new Runnable() {

@Override

public void run() {

try {

Thread.sleep(200);

countDownLatch.countDown();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}).start();

}

try{

countDownLatch.await();

}catch(InterruptedException e) {

e.printStackTrace();

}

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

}

eg:线程A , B ,C。 A,B运行完后运行C

CountDownLatch countDownLatch=new CountDownLatch(2);

new Thread(newRunnable() {

@Override

public void run() {

try{

Thread.sleep(2000);

}catch(InterruptedException e) {

e.printStackTrace();

}

System.out.println(Thread.currentThread().getName()+" done !");

countDownLatch.countDown();

}

},"A").start();

new Thread(new Runnable() {

@Override

public void run() {

try{

Thread.sleep(3000);

}catch(InterruptedException e) {

e.printStackTrace();

}

System.out.println(Thread.currentThread().getName()+" done !");

countDownLatch.countDown();

}

},"B").start();

new Thread(new Runnable() {

@Override

public void run() {

try{

countDownLatch.await();

}catch(InterruptedException e) {

e.printStackTrace();

}

System.out.println(Thread.currentThread().getName()+" done !");

}

},"C").start();

五.线程池初步

线程池基本思想就是 创建一些线程复用

long startTime=System.currentTimeMillis();

CountDownLatch countDownLatch=new CountDownLatch(65535);

ThreadPool threadPool=new ThreadPool(10000);

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

new Thread(new Runnable() {

@Override

public void run() {

try{

Thread.sleep(200);

countDownLatch.countDown();

}catch(InterruptedException e) {

e.printStackTrace();

}

}

}).start();

}

try{

countDownLatch.await();

}catch(InterruptedException e) {

e.printStackTrace();

}

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

上面的代码预计消耗时间是200ms但是 实际远远超出了我们的预期,这是因为新建线程消耗了一部分时间,cpu拥挤,并不会有那么多线程同时运行,会排队一会。

通过线程池可以优化上述代码的速度:

public class IdleThread extends Thread {   

 public LinkedBlockingQueuequeue;   

 public boolean started = true;    

public IdleThread(LinkedBlockingQueuequeue) {

this.queue = queue;

}

@Override

public void run() {

while (started) {

try {

//这个poll表示获取一个Runnable如果没有等待100ms

Runnable runnable = queue.poll(100, TimeUnit.MILLISECONDS);

if(runnable!=null)

runnable.run();

} catch (InterruptedException e) {

}

}

}

public void kill() {

started = false;

}

}

public class ThreadPool {

/**

*池最小大小

*/

private int minSize;

/**

*池最大大小

*/

private int maxSize;

LinkedBlockingQueue<Runnable>  tasks;

List<IdleThread> idleThreads;

public ThreadPool(int size){

this.maxSize=size;

this.minSize=size;

init();

}

private void init(){

tasks=new LinkedBlockingQueue<>(minSize);

idleThreads=new ArrayList<>(minSize);

for(inti=0;i<minSize;;i++){

IdleThread thread=new IdleThread(tasks);

idleThreads.add(thread);

thread.start();

}

}

public void execute(Runnable runnable) throws InterruptedException {

tasks.put(runnable);

}

public void shutdown(){

try{

for(IdleThread idleThread :idleThreads) {

idleThread.kill();

idleThread.interrupt();

}

}catch(Exception e){

e.printStackTrace();;

}

tasks.clear();

}

public void waitForAll(){

while(tasks.size()>0){

try{

Thread.sleep(0,1000);

}catch(InterruptedException e) {

e.printStackTrace();

}

}

}

}

相关文章

网友评论

      本文标题:java中Thread的深入了解(二)

      本文链接:https://www.haomeiwen.com/subject/wswujxtx.html