系统运维系列 之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详解及应用