java多线程资源互斥访问

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。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值