当涉及到多继承时,实现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有两个特征:互斥性和可见性。不仅可以解决一个线程看到对象处于不一致的状态,还可以保证进入同步方法或者同步代码块的每个线程,都看到由同一个锁保护之前所有的修饰效果。