系统运维系列 之java中实现多线程的方式

Posted 琅晓琳

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了系统运维系列 之java中实现多线程的方式相关的知识,希望对你有一定的参考价值。

1 前言:
多线程的意义:
(1)java一般被定义为网络编程语言,主要应用场景是服务器端编程,在用于服务器端编程的时候面临的重要问题就是客户端的并发请求,所以多线程对于java语言非常重要;
(2)多线程的存在是在抢CPU的资源和执行权,这样可以提高程序的执行速度和资源的使用效率;
(3)对于多核CPU可以充分发挥其优势,对于单核CPU可以防止阻塞。

2 应用:
(1)实现方式1:继承Thread类,重写该类的run方法【无返回值】

class MyThread extends Thread {
    private int i = 0;
    @Override
    public void run() {
        for (i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName() + " " + i);
        }
    }
}

public class ThreadTest {
    public static void main(String[] args) {
        Thread myThread1 = new MyThread();	// 创建一个新的线程
        Thread myThread2 = new MyThread();
        myThread1.start();	// 调用start()方法使得线程进入可执行状态
        myThread2.start();
    }
}

(2)实现方式2:实现Runnable接口,并重写该接口的run()方法【无返回值】

class MyRunnable implements Runnable {
    private int i = 0;
    @Override
    public void run() {
        for (i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName() + " " + i);
        }
    }
}

public class ThreadTest {
    public static void main(String[] args) {
        Runnable myRunnable = new MyRunnable(); // 创建一个Runnable实现类的对象
        Thread thread1 = new Thread(myRunnable); // 将myRunnable作为Thread target创建新的线程     
        thread1.start(); // 调用start()方法使得线程进入就绪状态     
        }
    }
}

(3)实现方式3:通过Callable和FutureTask创建线程【有返回值】
基本步骤为:
a: 创建Callable接口的实现类 ,并实现Call方法
b: 创建Callable实现类的实现,使用FutureTask类包装Callable对象,该FutureTask对象封装了Callable对象的Call方法的返回值
c: 使用FutureTask对象作为Thread对象的target创建并启动线程
d: 调用FutureTask对象的get()来获取子线程执行结束的返回值

class MyCallable implements Callable<Integer> {
    private int i = 0;
    // 与run()方法不同的是,call()方法具有返回值
    @Override
    public Integer call() {
        int sum = 0;
        for (i=0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName() + " " + i);
            sum += i;
        }
        return sum;
    }
}

public class ThreadTest {
    public static void main(String[] args) {
        Callable<Integer> myCallable = new MyCallable();    // 创建MyCallable对象
        FutureTask<Integer> ftask = new FutureTask<Integer>(myCallable); //使用FutureTask来包装MyCallable对象
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName() + " " + i);
            if (i == 3) {
                Thread thread = new Thread(ftask);   //FutureTask对象作为Thread对象的target创建新的线程
                thread.start();                  //线程进入到就绪状态
            }
        }
        System.out.println("主线程for循环执行完毕...");
        try {
            int sum = ftask.get();       //取得新创建的新线程中的call()方法返回的结果
            System.out.println("sum = " + sum);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

(4)实现方式4:通过线程池创建线程【有返回值】

class RunnableThread implements Runnable  
{     
    @Override
    public void run()  
    {  
        System.out.println("通过线程池方式创建的线程:" + Thread.currentThread().getName() + " ");  
    }  
}  

public class ThreadTest{
    private static int POOL_NUM = 20;    //线程池数量
    public static void main(String[] args) throws InterruptedException {
        //线程池
        ExecutorService executorService = Executors.newFixedThreadPool(5);  
        for(int i = 0; i<POOL_NUM; i++)  
        {  
            RunnableThread thread = new RunnableThread();
            //Thread.sleep(5000);
            executorService.execute(thread);
            //或者
            executorService.submit(thread); 
            //execute和submit的区别:
            //接收的参数不一样,submit可以是Callable、Runnable,execute只能是Runnable
            //submit有返回值,而execute没有
            //submit方便Exception处理 
        }
        //关闭线程池
        executorService.shutdown(); 
    }   
}

方法(3)和(4)可以组合起来一起使用,首先创建线程池,然后利用FutureTask对象的get()来获取子线程执行结束的返回值用于后续程序的处理。

3 补充:
(1)synchronized的作用:synchronized关键字是用来控制线程同步的,就是在多线程的环境下,控制synchronized代码段不被多个线程同时执行,既可以加在一段代码上,也可以加在方法上。

// 使用1:加在方法上
public synchronized void synMethod(){
//方法体
}
// 使用2:对某一代码块使用,synchronized后跟括号,括号里是变量,这样一次只有一个线程进入该代码块.此时,线程获得的是成员锁
public Object synMethod(Object obj){
synchronized(obj){
//一次只能有一个线程进入
	}
}

// 使用示例:
class MyThread extends Thread{
        @Override
        public void run() {
            synchronized (object) {
                i++;
                System.out.println("i:"+i);
                try {
                    System.out.println("线程"+Thread.currentThread().getName()+"进入睡眠状态");
                    Thread.currentThread().sleep(5000);
                } catch (InterruptedException e) {
                    // TODO: handle exception
                }
                System.out.println("线程"+Thread.currentThread().getName()+"睡眠结束");
                i++;
                System.out.println("i:"+i);
            }
     }
}

public class ThreadTest{
    private int i = 0;
    private Object object = new Object();
    public static void main(String[] args) throws IOException  {
    	Thread myThread1 = new MyThread();
    	Thread myThread1 = new MyThread();
        thread1.start();
        thread2.start();
    } 
} 

(2)使用特殊域变量volatile实现线程同步,其作用是:volatile修饰之后代表这个变量只能从共享内存中获取,禁止私有拷贝。

class BankTest{
        //需要同步的变量加上volatile
        private volatile int account = 10;
        public int getAccount() {
              return account;
        }
        //这里不再需要synchronized 
        public void save(int money) {
              account += money;
        }

参考资料:
https://zhuanlan.zhihu.com/p/47401636 Java多线程实现的四种方式
https://blog.csdn.net/aboy123/article/details/38307539 JAVA多线程实现的三种方式
https://zhuanlan.zhihu.com/p/79220097 java中的多线程
https://blog.csdn.net/lyly4413/article/details/87866726?utm_medium=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-1.control&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-1.control JAVA多线程下高并发的处理经验

以上是关于系统运维系列 之java中实现多线程的方式的主要内容,如果未能解决你的问题,请参考以下文章

系统运维系列 之Java中synchronized详解及应用

系统运维系列 之堆栈理解(java应用)

系统运维系列 之异常抛出后代码执行问题(java应用)

系统运维系列 之Java语言中解析json嵌套数组(干货亲测)

系统运维系列 之List实现深拷贝(java应用)

系统运维系列 之java中需要转义的特殊字符