作者微信 bishe2022

代码功能演示视频在页面下方,请先观看;如需定制开发,联系页面右侧客服
Java线程,多线程,线程同步,以及Java回调线程,还有难懂的synchronized

Custom Tab

曾几何时,有多少人听到了多线程就某花一紧,听到了线程的同步就感觉昏昏欲睡。那我们今天就聊一聊我的理解。线程是什么?Java中常用到的新建线程的场景?以及多线程和线程池的概念,最牛逼的还是要说清楚线程的同步。我跟人认为在Java的线程开发中,如果没有搞清楚同步的使用和JVM到底是什么机制实现的同步(本文中只针synchronized的同步做讲解lock另写)就不算知道Java的线程机制。废话不多说了,什么是线程这个问题大家自己去找度娘吧。那我们说说使用线程的应用场景。

1.Java中线程的创建和一般应用场景

在Java的api中是这样说明线程的:Java中实现线程的办法是继承Thread类或者实现Runnable接口,使用Thread.start()方法来启动线程。这是一个最基本的操作,不懂自己想办法。那么我们为什么需要这么做呢?在程序的设计中有一个阻塞的概念,个人觉得做好的例子就是ajax的同步和异步请求,同步请求就是阻塞的,异步的操作就是非阻塞的概念。换句话说,你使用异步的好处就是我们有时候需要使用新建一个线程的好处(Java中线程也返回值和没有没有返回值,后面会将)。我们新建一个线程单独去执行任务不会主线程产生阻塞,先这种场景就是使用线程的时候。

package com.test.thread.demo;  
  
public class ThreadDemo {  
    public static void main(String[] args){  
        ThreadTest threadTest = new ThreadTest();  
        threadTest.start();  
          
        RunnableDemo rdemo = new RunnableDemo();  
        Thread runnable = new Thread(rdemo);  
        runnable.start();  
    }  
  
      
}class RunnableDemo implements Runnable{  
  
    @Override  
    public void run() {  
        System.out.println("我是实现Runnable接口的线程");  
    }  
      
}  
  
class ThreadTest extends Thread{  
    public void run(){  
        System.out.println("我是集成Thread的线程");  
    }  
}

2.多线程和线程池的理解

         在Java中能够使用线程,那么我就一定能够同时创建n多个线程同时去执行主线程之外的任务。多线程可以简单的理解成同时创建很多个线程去运行。那么这里就产生了一个问题:如果创建的多个线程中每个线程使用的资源是单独的那一点问题都没有,大路朝天各走一边,如果不是呢?那就可能会出现一个非常严重的问题,对。。。。那就是死锁。我们如何避免死锁呢?当然是使用线程同步的方式咯。后面再说。

         线程池其实非常好理解,就跟数据库连接池是一个概念,但是我为什么还要讲呢?因为很多人虽然明白是什么道理,但是写起代码来还是比较晕头转向。所以我在这里给出demo。线程池的好处那也就不用多说了,数据库连接池有什么好处,线程池就有什么好处。。。。

package com.test.threadpool.demo;  
  
import java.util.concurrent.ExecutorService;  
import java.util.concurrent.Executors;  
  
public class ThreadPool {  
    public static void main(String[] args){  
        //此处是新建五个线程去执行任务  
        for(int i = 0;i<5;i++){  
            Thread th = new Thread(){  
                public void run(){  
                    System.out.println(this.getName());  
                }  
            };  
            th.start();  
        }  
          
        //此处是调用线程池去执行五个任务  
        //在Java的线程池中有很详细的api讲解,生产出来的四种模式的线程池对象的  
        //区别和作用,请自己深入,本实例主要为了说明多线程和线程池的区别  
        //虽然它们都是线程,启动方式不同是它们的根本区别  
        ExecutorService pool = Executors.newFixedThreadPool(5);  
        MyTask task1 = new MyTask();  
        MyTask task2 = new MyTask();  
        MyTask task3 = new MyTask();  
        MyTask task4 = new MyTask();  
        MyTask task5 = new MyTask();  
        pool.execute(task1);  
        pool.execute(task2);  
        pool.execute(task3);  
        pool.execute(task4);  
        pool.execute(task5);  
        pool.shutdown();  
    }  
  
}  
  
class MyTask implements Runnable {  
    @Override  
    public void run() {  
        System.out.println(Thread.currentThread().getName()+"执行任务");  
    }  
}

3.多线程的同步

在Java并发的多线程开发中都会遇到一个很严峻的问题,在第二节中已经说明了问题产生的原因,我们这里给出解决的方案和思路。首先我们来理解两个名词,第一个是” 并发“:我是这么理解的,并发的意思就是同时很多人一起去同一个地方拿同一个东西去干同一件事。第二是“同步”:我的理解是保证资源的使用的唯一性和协调性(比如按照一定规律使用)。比如很多人同时去一个地方上厕所,这么一件事情就是并发的事件,我们需要保证厕所的使用上是同步,以至于不会发生抢厕所导致隐私泄露的事情发生。是不是很是不能理解,不急,后面还有代码。。。。

避免并发事件中发生死锁的操作就是同步需要做的事情,在Java中实现同步有两个方式可以实现,第一使用synchronized关键字,第二就是使用lock上锁机制。本文针对synchronized做介绍。在使用synchronized关键上又有四种使用方法。记住:Java的同步只有两种方式,但是每个方式中实现的方法可以有很多种。

在使用synchronized关键字上上锁的对象是类对象(实例对象)或者类的Class对象。这是该方法使用的核心问题,能想明白了,证明你多Java的同步和线程已经到了高级篇了。我们说明一下类对象和类的Class对象,Student st = new Student();这里的st对象就是“类对象”。Class cz = st.getClass();这里的cz就是类的Class对象。记住有这两点区别,方便你后面看代码。

其实在这里我是打算贴上我的代码,分享给大家synchronized同步的使用方法和使用场景,但是最后我发现度娘比我强大多了,我还是放弃了,如果有觉得需要帮助或者看不懂以下引用的博文的,大家可以@我,我也欢迎大家打扰。

引用博文地址:http://www.cnblogs.com/devinzhang/archive/2011/12/14/2287675.html

4.线程的回调

说到线程回调,我想大家一定想到了js中的异步请求的回调方法。非常好,Java线程的回调其实就是一种可以回去返回值得线程。说白了就是执行一个线程,这个线程执行完了能够有返回值。有人是不是很郁闷,我使用线程也可以有返回值啊,当你有这个疑问的时候,请你仔细想想,run方法是void的声明的哦。你肯定又会想到,我可以声明一个全局变量来存储run之后的值啊,我想说,你确实可以这么做,但是可能有时候使用具有返回值的线程可能比你写个static的全局变量要好得多。

package com.test.callable.demo;  
  
import java.util.concurrent.Callable;  
import java.util.concurrent.ExecutorService;  
import java.util.concurrent.Executors;  
import java.util.concurrent.Future;  
  
public class CallableDemo {  
    //本实例中只是为了告诉大家具有返回值的线程是简单demo  
    //想要深入了解以及实现的机制以及原理可以自己学习或者研究源代码  
    //也可以在我博客中@Kyunchen  
    public static void main(String[] args){  
        //首先创建执行线程的线程池,  
        ExecutorService exs = Executors.newCachedThreadPool();  
        CallableThread ct = new CallableThread();//实例化任务对象  
        //大家对Future对象如果陌生,说明你用带返回值的线程用的比较少,要多加练习  
        Future<Object> future = exs.submit(ct);//使用线程池对象执行任务并获取返回对象  
        try {  
            Object sum = future.get();//当调用了future的get方法获取返回的值得时候  
            //如果线程没有计算完成,那么这里就会一直阻塞等待线程执行完成拿到返回值  
            System.out.println(sum);  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
        exs.shutdown();  
    }  
}  
  
/** 
 * 一定要记住在这里泛型声明的Object,表示的是返回值的对象的类型 
 * 也是call方法返回声明的类型 
 * 当然也是在main方法获取返回值的时候拿到的返回值对象的类型 
 * @author Kyunchen 
 * 
 */  
class CallableThread implements Callable<Object>{  
  
    @Override  
    public Object call() throws Exception {  
        //此处使用计算一到十的和然后返回  
        int sum = 0;  
        for(int i = 1;i<=10;i++){  
            sum += i;  
        }  
        return sum;  
    }  
      
}


转载自:http://blog.csdn.net/kyunchen/article/details/49702657





Home