Java多线程与线程同步
在Java中实现多线程通过以下2种方式:
1)实现implements 接口Runnable
2) 继承extends Java提供的类Thread,并重写方法run()
一般通过第一种方式来创建多线程.
import org.junit.Test;
class Work implements Runnable {
@Override
public void run() {
for(int i = 0; i<3; ++i){
System.out.println("thread "+Thread.currentThread().getName() +" is working " +i);
}
}
}
public class RunnableDemo {
@Test
public void test(){
Work work = new Work();
Thread thread1 = new Thread(work, "thread-1");
Thread thread2 = new Thread(work, "thread-2");
thread1.start();
thread2.start();
}
}
运行上述程序,发现线程thread1 和线程thread2交替执行
修改上述代码,增加一个变量count,修改后如下:
import org.junit.Test;
class Work implements Runnable {
int count = 0;
@Override
public void run() {
for(int i = 0; i<3; ++i){
System.out.println("thread "+Thread.currentThread().getName()
+" is working " +i+" couter is " +(++count));
}
}
}
public class RunnableDemo {
@Test
public void test(){
Work work = new Work();
Thread thread1 = new Thread(work, "thread-1");
Thread thread2 = new Thread(work, "thread-2");
thread1.start();
thread2.start();
}
}
结果发现两个线程对count这个变量的操作从打印结果来看有时候是一直累加,thread1在thread2操作的基础上进行累加
修改代码,修改如下:
import org.junit.Test;
class Work implements Runnable {
int count = 0;
public void add(){
++count;
}
@Override
public void run() {
add();
for(int i = 0; i<3; ++i){
System.out.println("thread "+Thread.currentThread().getName()
+" is working " +i+" couter is " +(count));
}
}
}
public class RunnableDemo {
@Test
public void test(){
Work work = new Work();
Thread thread1 = new Thread(work, "thread-1");
Thread thread2 = new Thread(work, "thread-2");
thread1.start();
thread2.start();
}
}
结果发现两个线程对count这个变量的操作从打印结果来看有时候是一直累加,thread1在thread2操作的基础上进行累加,更重要的是两个线程交替执行,有时候则不是,分析:
比如thread1第一次操作,并执行了add(),紧接着thread2执行第一次操作执行了add(),并执行了打印操作,输出结果count =2,紧接着又返回thread1第一次操作未完成的打印部分代码,也输出 count =2
引入synchronized这个关键字,继续调整代码,调整后代码如下:
import org.junit.Test;
class Work implements Runnable {
int count = 0;
public void add(){
++count;
}
@Override
public void run() {
synchronized(this){
add();
for(int i = 0; i<3; ++i){
add();
System.out.println("thread "+Thread.currentThread().getName()
+" is working " +i+" couter is " +(count));
}
}
}
}
}
public class RunnableDemo {
@Test
public void test(){
Work work = new Work();
Thread thread1 = new Thread(work, "thread-1");
Thread thread2 = new Thread(work, "thread-2");
thread1.start();
thread2.start();
}
}
从结果上来看,两个线程不是交替执行的,其中一个线程总是先执行完3次操作,另外一个线程接着执行3次操作,原因是使用了synchronized代码块,synchronized保证了在synchronized代码块中的代码执行的原子性
将上述部分代码封装到一个函数
import org.junit.Test;
class Work implements Runnable {
int count = 0;
public void add(){
++count;
}
public synchronized void loop(){
add();
for(int i = 0; i<3; ++i){
add();
System.out.println("thread "+Thread.currentThread().getName()
+" is working " +i+" couter is " +(count));
}
}
@Override
public void run() {
loop();
}
}
}
public class RunnableDemo {
@Test
public void test(){
Work work = new Work();
Thread thread1 = new Thread(work, "thread-1");
Thread thread2 = new Thread(work, "thread-2");
thread1.start();
thread2.start();
}
}
做上述改动后,结果还是顺序执行的,两个线程不是交替执行的,其中一个线程总是先执行完3次操作,另外一个线程接着执行3次操作
又因为synchronize可以放到方法里面,所以loop方法还可以这样写:
public void loop(){
synchronized(this){
add();
for(int i = 0; i<3; ++i){
add();
System.out.println("thread "+Thread.currentThread().getName()
+" is working " +i+" couter is " +(count));
}
}
}
当一个线程访问对象的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该对象中的非synchronized(this)同步代码块
class Counter implements Runnable{
private int count;
public Counter() {
count = 0;
}
public void countAdd() {
synchronized(this) {
for (int i = 0; i < 5; i ++) {
try {
System.out.println(Thread.currentThread().getName() + ":" + (count++));
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
//非synchronized代码块,未对count进行读写操作,所以可以不用synchronized
public void printCount() {
for (int i = 0; i < 5; i ++) {
try {
System.out.println(Thread.currentThread().getName() + " count:" + count);
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void run() {
String threadName = Thread.currentThread().getName();
if (threadName.equals("A")) {
countAdd();
} else if (threadName.equals("B")) {
printCount();
}
}
}
调用上述代码:
Thread thread1 = new Thread(counter, "A");
Thread thread2 = new Thread(counter, "B");
thread1.start();
thread2.start();
结果:
A:0
B count:1
A:1
B count:2
A:2
B count:3
A:3
B count:4
A:4
B count:5
问题:
问题1:
code snippet1:
Work work = new Work();
Thead thread1 = new Thread(work, “thread1”);
Thread thread2 = new Thread(work, “thread2”);
code snippet2:
Thead thread1 = new Thread(new Work(), “thread1”);
Thread thread2 = new Thread(new Work(), “thread2”);
这两个new Thread 的代码有什么区别?
snippet2 中两次new Work(), 故产生了两个不同的对象,另个对象对应两把对象锁,两把对象锁互不干扰