线程之间同步互斥的通信问题:
java用synchronized关键字做为多线程并发环境的执行有序性的保证手段之一。当一段代码会修改共享变量,这一段代码成为互斥区或临界区,为了保证共享变量的正确性,synchronized标示了临界区。
一个线程执行临界区代码过程如下:
1 获得同步锁
2 清空工作内存
3 从主存拷贝变量副本到工作内存
4 对这些变量计算
5 将变量从工作内存写回到主存
6 释放锁
可见,synchronized既保证了多线程的并发有序性,又保证了多线程的内存可见性。
volatile:volatile只能保证多线程的内存可见性,不能保证多线程的执行有序性。而最彻底的同步要保证有序性和可见性,例如synchronized。任何被volatile修饰的变量,都不拷贝副本到工作内存,任何修改都及时写在主存。因此对于Valatile修饰的变量的修改,所有线程马上就能看到,但是volatile不能保证对变量的修改是有序的。
volatile适合这种场景:一个变量被多个线程共享,线程直接给这个变量赋值。这是一种很简单的同步场景,这时候使用volatile的开销将会非常小。
内部类不可以在其外部类的main方法中直接new,因为内部类的实例化必须在外部类的实例化之后。
当出现两个线程同步进行的时候,会出现小概率事件,
那么我们就可以使用Synchronized修饰要被同步运行的方法。
package martina.TraditionalThread;
public class TraditionalThreadSynchronized {
public static void main(String[] args){
new TraditionalThreadSynchronized().init();
}
final static OutPuter outPuter=new OutPuter();
public void init(){
//两个线程
new Thread(new Runnable() {
@Override
public void run() {
while(true) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
System.out.println("Error:" + e.toString());
}
outPuter.output("YOUYOUYOUYOU");
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
while(true) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
System.out.println("Error:" + e.toString());
}
outPuter.output3("MEME");
}
}
}).start();
}
static class OutPuter{
public void output(String name){
//使用synchronized关键字实现同步
//由于两个线程都用到了outPuter对象,所以我们synchronized的参数要用outPuter对象
//如果是每一个线程都单独的创建了一个新的OutPuter对象,那么我们就要将下面的形参改为this
//如果是想要实现和一个static方法实现同步,则将下面的形参改为OutPuter.class(二进制字节码)
synchronized(outPuter) {
for (int i = 0; i < name.length(); i++) {
System.out.print("!:" + name.charAt(i));
}
System.out.println();
}
/*synchronized(this) {
for (int i = 0; i < name.length(); i++) {
System.out.print("!:" + name.charAt(i));
}
System.out.println();
}*/
/*//要用到OutPuter.class
synchronized(OutPuter.class) {
for (int i = 0; i < name.length(); i++) {
System.out.print("!:" + name.charAt(i));
}
System.out.println();
}*/
}
/**
* 最简单的办法就是用Synchronized关键字修饰给整个函数
* 那么将第二个线程使用output2的时候,依然可以和output的线程实现同步
* @param name
*/
public synchronized void output2(String name){
for (int i = 0; i < name.length(); i++) {
System.out.print("!:" + name.charAt(i));
}
System.out.println();
}
/**
* 这时候output函数中的synchronized的形参要用OutPuter.class,
* 因为static方法运行的时候是有一个对象与之关联,类的二进制字节码(OutPuter.class)在内存中也是一个对象
* 所以只有形参改为字节码的时候才能和static修饰的同步方法实现同步
* @param name
*/
public static synchronized void output3(String name){
for (int i = 0; i < name.length(); i++) {
System.out.print("!:" + name.charAt(i));
}
System.out.println();
}
};
}