Java多线程编程(volatile)

当涉及到多继承时,实现Runnable接口而不是继承Thread类,很有必要。

 

package com.java.mul;

import com.java.mul.extthread.Alogin;
import com.java.mul.extthread.BLogin;

public class multest {

	public static void main(String[] args) throws InterruptedException {
		// TODO Auto-generated method stub
		PrintString printStringService = new PrintString();
		new Thread(printStringService).start();
		System.out.println("stop="+ Thread.currentThread().getName());
		printStringService.setContinuePrint(false);

	}
}


package com.java.mul;

public class PrintString implements Runnable{
	private boolean isContinuePrint = true;
	public boolean isContinuePrint() {
		return isContinuePrint;
	}
	public void setContinuePrint(boolean isContinuePrint) {
		this.isContinuePrint = isContinuePrint;
	}
	public void printStringMethod() {
		try {
			while(isContinuePrint == true) {
				System.out.println("threadName=" + Thread.currentThread().getName());
				Thread.sleep(1000);
			}
			
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	@Override
	public void run() {
		// TODO Auto-generated method stub
		printStringMethod();
	}
	
}

以上实例代码的格式,一旦运行在-server服务器模式中,64bit的JVM上时,就会出现死循环,解决办法是用volatile关键字。

volatile关键字的作用是强制从公共堆栈中取得变量的值,而不是从线程私有数据栈中取得变量的值。

package com.java.mul;

import com.java.mul.extthread.Alogin;
import com.java.mul.extthread.BLogin;

public class multest {

	public static void main(String[] args) throws InterruptedException {
		// TODO Auto-generated method stub
		RunThread thread = new RunThread();
		thread.start();
		Thread.sleep(1000);
		thread.setRunning(false);
		System.out.println("value false");

	}
}

package com.java.mul;

public class RunThread extends Thread{
	private boolean isRunning = true;
	public boolean isRunning() {
		return isRunning;
	}
	public void setRunning(boolean isRunning) {
		this.isRunning = isRunning;
	}
	@Override
	public void run() {
		System.out.println("enter");
		while(isRunning == true) {
			
		}
		System.out.println("stop");
	}
}

在启动RunThread线程时,变量private boolean isRunning = true;存在于公共堆栈及线程的私有堆栈中。在JVM被设置为-server模式时,为了线程运行的效率,线程一直在私有堆栈中取得isRunning的值是true。而代码thread.setRunning(false);虽然被执行,更新的却是公共堆栈中的isRunning变量值false,所以一直就是死循环的状态。解决这样的问题要用volatile关键字,使得线程访问isRunning变量时,强制性从公共堆栈中进行取值。

更改如下

package com.java.mul;

import com.java.mul.extthread.Alogin;
import com.java.mul.extthread.BLogin;

public class multest {

	public static void main(String[] args) throws InterruptedException {
		// TODO Auto-generated method stub
		RunThread thread = new RunThread();
		thread.start();
		Thread.sleep(1000);
		thread.setRunning(false);
		System.out.println("value false");

	}
}

package com.java.mul;

public class RunThread extends Thread{
	volatile private boolean isRunning = true;
	public boolean isRunning() {
		return isRunning;
	}
	public void setRunning(boolean isRunning) {
		this.isRunning = isRunning;
	}
	@Override
	public void run() {
		System.out.println("enter");
		while(isRunning == true) {
			
		}
		System.out.println("stop");
	}
}

volatile变量最致命的缺点是不支持原子性。(只能用来修饰变量)解决的是可见性问题,而不是原子性问题。

除了可以用synchronized实现原子性,还可以用AtomicInteger

package com.java.mul;

import com.java.mul.extthread.Alogin;
import com.java.mul.extthread.BLogin;

public class multest {

	public static void main(String[] args) throws InterruptedException {
		// TODO Auto-generated method stub
		RunThread countService = new RunThread();
		Thread t1 = new Thread(countService);
		t1.start();
		Thread t2 = new Thread(countService);
		t2.start();
		Thread t3 = new Thread(countService);
		t3.start();
		Thread t4 = new Thread(countService);
		t4.start();
		
		


	}
}

package com.java.mul;

import java.util.concurrent.atomic.AtomicInteger;

public class RunThread extends Thread{
	private AtomicInteger count = new AtomicInteger(0);


	@Override
	public void run() {
		for(int i = 0;i<10000;i++) {
			System.out.println(count.incrementAndGet());
		}
	}
}

synchronized的可见性:

package com.java.mul;

public class Service {
	private boolean isCon = true;
	public void runMethod() {
		while(isCon==true) {
			
		}
		System.out.print("stop");
	}
	public void stopM() {
		isCon = false;
	}

}

package com.java.mul;

public class MyThreadA extends Thread{
	private Service service;
	public MyThreadA(Service service) {
		super();
		this.service = service;
	}
	
	@Override
	public void run() {
		service.runMethod();
	}
}

package com.java.mul;

public class MyThreadB extends Thread{
	private Service service;
	public MyThreadB(Service service) {
		super();
		this.service = service;
	}
	
	@Override
	public void run() {
		service.stopM();
	}
}

package com.java.mul;

import com.java.mul.extthread.Alogin;
import com.java.mul.extthread.BLogin;

public class multest {

	public static void main(String[] args) throws InterruptedException {
		// TODO Auto-generated method stub
		Service service = new Service();
		MyThreadA a = new MyThreadA(service);
		a.start();
		Thread.sleep(1000);
		MyThreadB b = new MyThreadB(service);
		b.start();
		System.out.println("stop send");
		
		


	}
}

这个代码,MyThreadB并没有将isCon变为false,因为各线程之间,数据没有可视性。因此可以加关键字。

package com.java.mul;

public class Service {
	private boolean isCon = true;
	private Object o = new Object();
	public void runMethod() {
		while(isCon==true) {
			synchronized(o) {
				
			}
		}
		System.out.print("stop");
	}
	public void stopM() {
		isCon = false;
	}

}

synchronized有两个特征:互斥性和可见性。不仅可以解决一个线程看到对象处于不一致的状态,还可以保证进入同步方法或者同步代码块的每个线程,都看到由同一个锁保护之前所有的修饰效果。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值