举一个例子来解释java多线程同步锁的用法:有first,second,third,forth四个线程,first输出1,second输出2,third输出3,forth输出4。要求, 同时启动四个线程, 按顺序输出1234, 且未无限循环输出。
首先是jdk5的lock和unclock,lock表示Lock对象执行了锁定操作,其他的线程都必须等这个线程完成,unlock则并释放锁之后,才能执行被锁住的代码块。
public class Test1 {
private static int state = 0;
private static Lock lock = new ReentrantLock();//通过JDK5中的锁来保证线程的访问的互斥
public static void main(String[] args) {
First first = new First();
Second second = new Second();
Third third = new Third();
Forth forth = new Forth();
first.start();
second.start();
third.start();
forth.start();
}
static class First extends Thread{
@Override
public void run() {
while(true){
lock.lock();
if(state % 4 ==0){
state++;
System.out.println(0);
}
lock.unlock();
}
}
}
static class Second extends Thread{
@Override
public void run() {
while(true){
lock.lock();
if(state % 4 ==1){
state++;
System.out.println(1);
}
lock.unlock();
}
}
}
static class Third extends Thread{
@Override
public void run() {
while(true){
lock.lock();
if(state % 4 ==2){
state++;
System.out.println(3);
}
lock.unlock();
}
}
}
static class Forth extends Thread{
@Override
public void run() {
while(true){
lock.lock();
if(state % 4 ==3){
state++;
System.out.println(4);
}
lock.unlock();
}
}
}
}
最终输出的结果是无序的,因为4个线程同时争夺cpu的执行权。
接下来是:Semphore(翻译过来就是信号的意思)
Semphore,完成对信号量的控制,可以控制某个资源可以被同时访问的个数,通过acquire()获取一个许可,如果没有就等待,而release()释放一个许可。通过代码可以更好的理解
public class Test2 { public static Semaphore sem1; public static Semaphore sem2; public static Semaphore sem3; public static Semaphore sem4; static class First extends Thread{ @Override public void run() { try { while(true){ sem1.acquire(); //sem1的资源数减一后,资源数为0,然后自己阻塞起来 System.out.println(1); sem2.release(); //sem2资源数加一,不再为0,可以开始运行 } }catch (InterruptedException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } } } static class Second extends Thread{ @Override public void run() { try { while(true){ sem2.acquire(); System.out.println(2); sem3.release(); } }catch (InterruptedException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } } } static class Third extends Thread{ @Override public void run() { try { while(true){ sem3.acquire(); System.out.println(3); sem4.release(); } }catch (InterruptedException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } } } static class Forth extends Thread{ @Override public void run() { try { while(true){ sem4.acquire(); System.out.println(4); sem1.release(); } }catch (InterruptedException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } } } public static void main(String[] args) { sem1 = new Semaphore(1); sem2 = new Semaphore(1); sem3 = new Semaphore(1); sem4 = new Semaphore(1); //1代表是1个信号量,也可以理解为资源数,进行初始化用的 try { // 不要有sem1.acquire() sem2.acquire(); //把sem2初始化时候给的资源数全部减1,只让sem1拥有资源数 sem3.acquire(); sem4.acquire(); } catch (InterruptedException e) { e.printStackTrace(); }
First first = new First(); Second second = new Second(); Third third = new Third(); Forth forth = new Forth(); first.start(); second.start(); third.start(); forth.start(); }
最终结果为:
补充知识点:volatile,保证被修饰的变量在读写前都会与主存交互更新。一个变量被volatile修饰后,则不同线程对这个变量进行操作时,总是从内存中读取最新值,即每次更新对其他线程都是立即可见的。注意立即可见这几个字。。
public class Test3 {
volatile static int state = 0;
static class First extends Thread{
@Override
public void run() {
while(true){
if(state%4==0){
System.out.println("1");
state++;
}
}
}
}
static class Second extends Thread{
@Override
public void run() {
while(true){
if(state%4==1){
System.out.println("2");
state++;
}
}
}
}
static class Third extends Thread{
@Override
public void run() {
while(true){
if(state%4==2){
System.out.println("3");
state++;
}
}
}
}
static class Forth extends Thread{
@Override
public void run() {
while(true){
if(state%4==3){
System.out.println("4");
state++;
}
}
}
}
public static void main(String[] args) {
First first = new First();
Second second = new Second();
Third third = new Third();
Forth forth = new Forth();
first.start();
second.start();
third.start();
forth.start();
}
}
最终结果为: