控制多线程输出
- 线程一,循环输出的1,线程二,循环输出2,线程三,循环输出3,写一个程序,控制这三个线程循环输出1,2,3,1,2,3,…
- 这个欠缺的知识有点多,一时间不知道怎么弄,这里先补充一下
Java实现线程——不使用锁实现
- 实现runnable接口的具体类
- 重写runnable方法,然后在一个thread对象中传入对应的新实例,创建对应线程,然后进行运行
public static void main(String[] args) {
Thread t1 = new Thread(new ThreadTest(1));
Thread t2 = new Thread(new ThreadTest(2));
Thread t3 = new Thread(new ThreadTest(3));
t1.start();
t2.start();
t3.start();
}
static class ThreadTest implements Runnable{
int num = 0;
ThreadTest(int val){
num = val;
}
// define recursive function
private void printNum() throws InterruptedException {
while(true){
System.out.print(num);
Thread.sleep(100);
}
}
@Override
public void run() {
try {
printNum();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
下述是直接实现的效果,并不是完全的123顺序,所以这个方法并不合理!
版本一,通过全局变量实现控制输出的123
- 这里虽然有多个线程,但是他们都是Main的内部类,以及内部实例,是共享一个静态变量的current,所以通过current进行设置即可!
public class Main {
private static int current = 1;
public static void main(String[] args) {
Thread t1 = new Thread(new ThreadTest(1));
Thread t2 = new Thread(new ThreadTest(2));
Thread t3 = new Thread(new ThreadTest(3));
t1.start();
t2.start();
t3.start();
}
static class ThreadTest implements Runnable{
int num = 0;
ThreadTest(int val){
num = val;
}
// define recursive function
private void printNum() throws InterruptedException {
while(true){
if (current == num){
System.out.print(num);
current ++;
}
if(current == 4) current = 1;
Thread.sleep(100);
}
}
@Override
public void run() {
try {
printNum();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
问题
- 如果不使用对应锁进行控制,三个线程同时在输出前阻塞,然后输出顺序就没有办法控制了!仅仅是在这个简单程序出问题的概率比较低,如果复杂程序出问题的概率就高了!
使用synchronized关键实现——使用锁实现
synchronized关键字介绍
- 修饰函数,多个线程只能互斥访问这个函数
- 修饰代码块,多个线程只能访问特定的代码块(需要使用对象锁)
不使用synchronized实现方法
使用synchronized方法效果
- 下文使用了synchronized方法之后的效果
public class Main {
private static int current = 1;
private static final Object lock = new Object();
public static void main(String[] args) {
Thread t1 = new Thread(new ThreadTest(1));
Thread t2 = new Thread(new ThreadTest(2));
Thread t3 = new Thread(new ThreadTest(3));
t1.start();
t2.start();
t3.start();
}
static class ThreadTest implements Runnable{
int num = 0;
ThreadTest(int val){
num = val;
}
// define recursive function
private void printNum() throws InterruptedException {
synchronized (lock){
while(true){
current ++;
System.out.println(current);
Thread.sleep(100);
}
}
}
@Override
public void run() {
try {
printNum();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
使用synchronized、wait和notify关键字实现
具体实现思路
- 使用state来表示当前应该的打印那个字母,
- 每一个线程打印字母之后,就要更新state并且唤醒正在等待的线程
public class Main {
private static int current = 1;
private static final Object lock = new Object();
public static void main(String[] args) {
Thread t1 = new Thread(new Runnable(){
@Override
public void run(){
for(int i = 0;i < 100;i ++){
synchronized(lock){
// judge whether th current thread should print the num
try {
// if the current thread should not print num ,wait until the current changed
while (current % 3 != 1) {
lock.wait();
}
System.out.println(1);
current ++;
lock.notifyAll();
}catch(InterruptedException e){
e.printStackTrace();
}
}
}
}
});
Thread t2 = new Thread(new Runnable(){
@Override
public void run() {
// traverse 100 times
for(int i = 0;i < 100;i ++){
synchronized(lock){
try{
while(current % 3 != 2){
lock.wait();
}
System.out.println(2);
current ++;
lock.notifyAll();
}catch(InterruptedException e){
e.printStackTrace();
}
}
}
}
});
Thread t3 = new Thread(new Runnable(){
@Override
public void run(){
for(int i = 0;i < 100;i ++){
synchronized(lock){
try{
while(current % 3 != 0) {
lock.wait();
}
System.out.println(3);
current ++;
lock.notifyAll();
}catch(InterruptedException e){
e.printStackTrace();
}
}
}
}
});
t1.start();
t2.start();
t3.start();
}
}
这里有几个东西还是需要记住的
- 重写的是Overirde,第一个字母是大写
- notify和wait是会出现interruptedException异常
- 打印输出异常信息是e.printStackTrace()