java多线程资源互斥访问

    xiaoxiao2021-03-25  140

    java多线程——资源互斥访问

    本文首先介绍一下java实现多线程的几种方式,再介绍一下如何实现资源的互斥访问,最后介绍生产环境中线程池的应用。 好,下面上货。

    一、创建线程的两种方式:

    1、继承Thread类。 package com.xueyoucto.xueyou; public class FirstThread extends Thread { public FirstThread() { } public FirstThread(String name) { super(name); } @Override public void run() { for (int i = 0; i < 50; i++) { System.out.println(Thread.currentThread().getName() + "\t" + i); } } } 2、实现Runnable接口。 package com.xueyoucto.xueyou; public class SecondThread implements Runnable { @Override public void run() { for (int i = 0; i < 50; i++) { System.out.println(Thread.currentThread().getName() + "\t" + i); } } } 主程序中调用: package com.xueyoucto.xueyou; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; /** * Hello world! */ public class App { public static int[] GLOBALARRAY = new int[50]; public static ThreadLocal<String[]> TLGLOBALARRAY = new ThreadLocal<String[]>() { @Override protected String[] initialValue() { String[] temp = new String[50]; for (int i = 0; i < temp.length; i++) { temp[i] = String.valueOf(i + 100); } return temp; } }; static { for (int i = 0; i < GLOBALARRAY.length; i++) { GLOBALARRAY[i] = i; } } public static void main(String[] args) { //使用继承的方式创建线程 FirstThread firstThread = new FirstThread("aaThread"); FirstThread firstThread2 = new FirstThread("bbThread"); firstThread.start(); firstThread2.start(); //实现Runnable接口 new Thread(new SecondThread(), "cc-Thread").start(); new Thread(new SecondThread(), "dd-Thread").start(); } } 运行结果: 输出的数据是穿插的,每个线程都会有对应的输出。

    二、资源的互斥访问

    1、synchornized(){}方式 package com.xueyoucto.xueyou; public class ReadPublicArray implements Runnable { @Override public void run() { synchronized (App.GLOBALARRAY) { for (int i = 0; i < App.GLOBALARRAY.length; i++) { System.out.println(Thread.currentThread().getName() + "\t" + App.GLOBALARRAY[i]); } } } } 2、lock方式 package com.xueyoucto.xueyou; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class LockReadPublicArray implements Runnable { //这里的锁应该是所有的线程使用同一个锁 public static Lock lock = new ReentrantLock(); @Override public void run() { lock.lock(); try { for (int i = 0; i < App.GLOBALARRAY.length; i++) { System.out.println(Thread.currentThread().getName() + "\t" + App.GLOBALARRAY[i]); } } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } } 3、ThreadLocal方式 package com.xueyoucto.xueyou; public class ThreadLocalReadPublicArray implements Runnable { @Override public void run() { String[] tlArray = App.TLGLOBALARRAY.get(); //在此修改每一个元素的值 for (int i = 0; i < tlArray.length; i++) { tlArray[i] += "==" + Thread.currentThread().getName() + "=="; } //打印的时候发现,是不一样的,所以ThreadLocal对每一个线程都给了一个副本 for (int i = 0; i < tlArray.length; i++) { System.out.println(Thread.currentThread().getName() + "\t" + tlArray[i]); } } } 在主程序中使用 package com.xueyoucto.xueyou; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; /** * Hello world! */ public class App { public static int[] GLOBALARRAY = new int[50]; public static ThreadLocal<String[]> TLGLOBALARRAY = new ThreadLocal<String[]>() { @Override protected String[] initialValue() { String[] temp = new String[50]; for (int i = 0; i < temp.length; i++) { temp[i] = String.valueOf(i + 100); } return temp; } }; static { for (int i = 0; i < GLOBALARRAY.length; i++) { GLOBALARRAY[i] = i; } } public static void main(String[] args) { //互斥访问synchornized new Thread(new ReadPublicArray(),"Thread-first").start(); new Thread(new ReadPublicArray(),"Thread-second").start(); //采用lock的方式对进行代码块进行锁定 new Thread(new LockReadPublicArray(), "Thread-first").start(); new Thread(new LockReadPublicArray(), "Thread-second").start(); //采用ThreadLocal的方式实现线程对同一变量的互斥访问,本质上是TheadLocal为每一个线程产生了一个副本 new Thread(new ThreadLocalReadPublicArray(), "Thread-first").start(); new Thread(new ThreadLocalReadPublicArray(), "Thread-second").start(); } } 运行结果: 每个线程访问之后才会执行下一个线程,能够实现对静态变量的互斥访问。

    三、线程池的常规使用(jkd1.5+)

    具体的应用还可以在java.util.concurrent包中去看 package com.xueyoucto.xueyou; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; /** * Hello world! */ public class App { public static int[] GLOBALARRAY = new int[50]; public static ThreadLocal<String[]> TLGLOBALARRAY = new ThreadLocal<String[]>() { @Override protected String[] initialValue() { String[] temp = new String[50]; for (int i = 0; i < temp.length; i++) { temp[i] = String.valueOf(i + 100); } return temp; } }; static { for (int i = 0; i < GLOBALARRAY.length; i++) { GLOBALARRAY[i] = i; } } public static void main(String[] args) { ExecutorService pool = Executors.newFixedThreadPool(3); pool.execute(new SecondThread()); pool.execute(new SecondThread()); pool.execute(new SecondThread()); pool.shutdown(); // Disable new tasks from being submitted try { //判断是否所有线程已经执行完毕 boolean isFinish = pool.awaitTermination(1,TimeUnit.MILLISECONDS); System.out.println(isFinish +"=========================="); //如果没有执行完 if(!isFinish){ //线程池执行结束 不在等待线程执行完毕,直接执行下面的代码 pool.shutdownNow(); } } catch (InterruptedException e) { e.printStackTrace(); } finally { } //只给线程池中的线程1毫秒,然后就继续执行 System.out.println("it is ok !!!"); } } 运行结果: 从结果可以看出,线程池中的线程还没有结束,下面的System.out.println("it is ok !!!");就已经被打印出来了。这里实现了对线程池中的线程进行控制。 需要注意的是这几个方法: pool.shutdown();//不允许其他线程加入线程池 pool.shutdownNow();//停止线程池的阻塞,执行线程池后的代码。 pool.waitTermination();//判断在参数时间内,线程池中的线程是否全部执行完,执行完返回true,没执行完,返回false。
    转载请注明原文地址: https://ju.6miu.com/read-4705.html

    最新回复(0)