今天仔细看了一些视频和网上的问题解答。总结了一点写多线程程序的步骤,
步骤
1.最好先不要加入synchronized或lock等关键字,先将你要实现的功能写好
2.写好并测试没问题后再实现Runnable接口或者继承Thread类(建议前面一种)
3.分析线程安全问题,引发线程安全问题的前提就是看是否有多个线程操作统一个数据并且操作代码不止一行,如果存在,应该就要加同步关键字了
4.加同步关键字时如果用的是synchronized关键字或synchronized同步代码块,需要注意的是不同线程的锁一定要是一样的,否则达不到同步的效果
代码分析
下面是今天完成的一个多线程的程序,可以理解为一个多生产多消费的程序,生产模式为:只要物品数小于10,就要生产,当生产到10个时,停止生产,等待消费者消费。消费模式为:只要有物品,就可以消费。每当消费一个后,就要提醒生产者应该生产了,然后消费者继续消费,当消费到0时,停止消费,等待生产者生产。
可能遇到的问题
有时候会发现结果会很有规律,生产10个消费10个,但这其实时由于cpu太快的原因造成,多运行一会儿会发现后面会有不规律结果产生,或者在代码中将生产或消费的速度适当调整就会出现不规律的结果
代码
package thread;
class Test
{
//开始物品个数为0
private int count = 0;
//生产方法
public void add()
{
//不断生产
while(true)
{
//生产时由共享数据操作且大于一行,所以要同步
synchronized(this)
{
//最大生产的10个,只要获得执行权并且物品小于10就生产
if(count < 10)
{
count++;
System.out.println(Thread.currentThread().getName() + "生产了............" + count);
//只要生产了,就说明有物品,就可以消费,所以在这里可以唤醒消费线程
this.notify();
}
else
{
try {
//当生产到10个时,就需要等待消费者消费了
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
//消费方法
public void remove()
{
// 不断消费
while(true)
{
//消费方法也有对共享数据的操作且不知一行,所以此处要同步
synchronized(this)
{
// 当物品数不等于零且有执行权时,就可以消费
if(count != 0)
{
for(int i=0; i<2000; i++) {}//设置一个延迟,方便测试,这是无关代码
System.out.println(Thread.currentThread().getName() + "消费了,," + count);
count--;
// 只要物品数减少了,说明就小于10了,就唤醒生产线程生产
this.notify();
}
else
{
try {
// 当消费到零时,就等待生产线程生产,不需要唤醒生产线程,因为前面一定会有一次唤醒动作
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
}
//生产任务
class Thread1 implements Runnable
{
private Test t;
public Thread1(Test t)
{
this.t = t;
}
@Override
public void run() {
t.add();
}
}
//消费任务
class Thread2 implements Runnable
{
private Test t;
public Thread2(Test t)
{
this.t = t;
}
@Override
public void run() {
t.remove();
}
}
public class ThreadDemo {
public static void main(String[] args)
{
// 此程序即可以是单生产单消费模式,也可以是多生产多消费模式
// 下面模仿的是一个三生产三消费模式
Test t = new Test();
Thread1 t0 = new Thread1(t);
Thread2 t1 = new Thread2(t);
Thread add0 = new Thread(t0);
Thread add1 = new Thread(t0);
Thread add2 = new Thread(t0);
Thread remove0 = new Thread(t1);
Thread remove1 = new Thread(t1);
Thread remove2 = new Thread(t1);
add0.start();
add1.start();
add2.start();
remove0.start();
remove1.start();
remove2.start();
}
}