实现三个线程交替打印1-100的四种姿势
使用synchronized关键字
synchronized关键字常用写法
使用synchronized关键字的写法比较多,常用的有如下几种
public class UseSync{
// 持有的锁是UseSync.java 对应的Class类的对象
synchronized public static void testMethod() {
}
// 持有的锁是UseSync.java 对应的Class类的对象
public void testMethod2() {
synchronized (UseSync.class) {
}
}
// 持有的锁是UseSync.java类的对象
synchronized public void testMethod3() {
}
// 持有的锁是UseSync.java类的对象
public void testMethod4() {
synchronized (this) {
}
}
// 持有的锁是字符串abc类的对象
public void testMethod5() {
synchronized ("abc") {
}
}
}
交替打印
锁是非this对象(例子使用object)
- 实现Runnable
class PrintSequence implements Runnable {
int numOfThreads;
static int count=1;
static Object monitor = new Object(); //static
public PrintSequence( int nubOfThreads) {
this.numOfThreads = nubOfThreads;
}
@Override
public void run() {
print();
}
private void print() {
while (count<99) {
synchronized (monitor) {
while(count % 3 != numOfThreads) {
try {
monitor.wait();
} catch (InterruptedException e){
e.printStackTrace();
}
}
System.out.println("ThreadId [" + numOfThreads
+ "] printing -->"
+ count);
count++;
monitor.notifyAll();
}
}
}
}
- 运行类
public class Test {
public static void main(String[] args) {
PrintSequence runnable1=new PrintSequence(1);
PrintSequence runnable2=new PrintSequence(2);
PrintSequence runnable3=new PrintSequence(0);
Thread t1=new Thread(runnable1,"T1");
Thread t2=new Thread(runnable2,"T2");
Thread t3=new Thread(runnable3,"T3");
t1.start();
t2.start();
t3.start();
}
}
锁是持有对应的Class类的对象
- 继承Thread的方法创建线程A
public class ThreadA extends Thread {
private Service s ;
public ThreadA(Service s) {
this.s = s;
}
@Override
public void run() {
s.printCount(this.getName());
}
}
- 实现Runnable的方法创建线程C
public class RunnableC implements Runnable {
private Service s ;
public RunnableC(Service s) {
this.s = s;
}
@Override
public void run() {
s.printCount2(Thread.currentThread().getName());
}
}
- 封装Service。
public class Service {
private volatile static int count;
public Service(int count){
this.count = count;
}
public void printCount(String threadName) {
synchronized (Service.class) {
if (count <=100) {
System.out.println("Thread " + Thread.currentThread().getName() + " = " + count ++ );
}
}
}
public void printCount2(String threadName) {
synchronized (Service.class) {
if (count <=100) {
System.out.println("Thread " + Thread.currentThread().getName() + " = " + count++);
}
}
}
}
- 运行类代码如下
public class Print3 {
public static void main(String[] args) throws InterruptedException {
int count = 1;
Service s = new Service(count);
for ( int i=0; i< 34;i++) {
ThreadA a = new ThreadA(s);
a.setName("A");
Thread b = new Thread("B") {
@Override
public void run() {
s.printCount(this.getName());
}
};
Runnable r = new RunnableC(s);
Thread c = new Thread(r, "C");
a.start();
a.join();
b.start();
b.join();
c.start();
}
}
}
如果注释掉Print3.java中的join(), 可用于验证当锁是持有对应的Class类的对象时,同步方法呈现同步效果。即运行完一个同步方法才会运行下一个同步方法。注意,3 个线程调用顺序是random,但是结果是同步的。
如果想保持A B C 顺序,可以使用join()。 方法join()具有串联执行的作用:你不销毁,我不往下走,可以支持多个线程的等待。 join()在内部使用wait()方法进行等待,会释放锁,而synchronized关键字一直持有锁。
使用ReentrantLock 和 Condition
- 封装Service
public class MyService{
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
volatile private int nextWhoPrint = 1;
volatile private int count = 1;
public void testMethod1() {
try {
lock.lock();
while(nextWhoPrint!=1) {
condition.await();
}
if (count <=100) {
System.out.println("Thread A " + count++);
}
nextWhoPrint = 2;
condition.signalAll();
lock.unlock();
}catch (InterruptedException e) {
e.printStackTrace();
}
}
public void testMethod2() {
try {
lock.lock();
while(nextWhoPrint!=2) {
condition.await();
}
if (count <=100) {
System.out.println("Thread B " + count++);
}
nextWhoPrint = 3;
condition.signalAll();
lock.unlock();
}catch (InterruptedException e) {
e.printStackTrace();
}
}
public void testMethod3() {
try {
lock.lock();
while(nextWhoPrint!=3) {
condition.await();
}
if (count <=100) {
System.out.println("Thread C " + count++);
}
nextWhoPrint = 1;
condition.signalAll();
lock.unlock();
}catch (InterruptedException e) {
e.printStackTrace();
}
}
}
- 创建3个线程
public class MyThreadA extends Thread {
private MyService service;
public MyThreadA(MyService service) {
super();
this.service = service;
}
@Override
public void run() {
service.testMethod1();
}
}
public class MyThreadB extends Thread {
private MyService service;
public MyThreadB(MyService service) {
super();
this.service = service;
}
@Override
public void run() {
service.testMethod2();
}
}
class MyThreadC extends Thread {
private MyService service;
public MyThreadC(MyService service) {
super();
this.service = service;
}
@Override
public void run() {
service.testMethod3();
}
}
- 创建运行类
public class Lock3 {
public static void main(String[] args) throws InterruptedException {
MyService service =new MyService();
for( int i=0;i<34;i++) {
MyThreadA a = new MyThreadA(service);
a.start();
MyThreadB b = new MyThreadB(service);
b.start();
MyThreadC c = new MyThreadC(service);
c.start();
}
}
}
使用信号量
public class ThreadPrint100 {
// 以A开始的信号量,初始信号量数量为1
private static final Semaphore A = new Semaphore(1);
// B、C信号量,A完成后开始,初始信号数量为0
private static final Semaphore B = new Semaphore(0);
private static final Semaphore C = new Semaphore(0);
private volatile static int count = 1;
//设置一个控制变量
private static boolean loop = true;
public static class ThreadA extends Thread {
@Override
public void run() {
try {
for (int i = 0; i < 34 && loop ; i++) {
A.acquire();// A获取信号执行,A信号量减1,当A为0时将无法继续获得该信号量
System.out.println("Thread A: " + count);
count ++;
B.release();// B释放信号,B信号量加1(初始为0),此时可以获取B信号量
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static class ThreadB extends Thread {
@Override
public void run() {
try {
for (int i = 0; i <33 && loop; i++) {
B.acquire();
System.out.println("Thread B: " + count);
count ++;
C.release();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static class ThreadC extends Thread {
@Override
public void run() {
try {
for (int i = 0; i < 33 && loop; i++) {
C.acquire();
System.out.println("Thread C: " + count);
count ++;
A.release();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws InterruptedException {
new ThreadA().start();
new ThreadB().start();
new ThreadC().start();
}
}