您的位置:首页 > 编程语言 > Java开发

并发-----java多线程理解与总结

2015-09-28 16:13 459 查看
------- android培训java培训、期待与您交流! ----------

多线程Thread:一个进程中拥有多个可执行路径,一个程序至少有一个进程,而一个进程至少有一个线程;

java对多线程的支持方案:1继承Thread类,2实现Runnable方法

特点:由于线程是程序的多条执行路径,所以执行权CPU说了说,多线程具有随机性和并发性

Thread类概述:

run()方法概述:这个方法里封装了线程要执行的代码,也就是说我们将想要多线程执行的代码的地方,如果对象直接调用则不是多线程;
start()方法:让线程就绪,执行run()方法体;
在线程就绪前,也就是start()调用前,我们可以设置线程的优先级,守护线程等,易于理解
isLive()测试线程是否是激活状态
interrupt(),中断线程
thread类试图通过自己的方法来控制线程合理的在理想状态下执行,但是cpu的多核多线程技术使得他不可能理想的完成,所以,其他的方法就看api了解
线程的生命周期图



cpu操作是具有原子性的,所以判断线程时候存在问题的条件为:

是否是多线程 ,这个必须是,因为我们编写的就是多线程程序
是否有共享代码,从这一步就要考虑问题的存在了,因为每个线程都有自己的栈内存,程序计数器等
是否是同一把锁,这个往往被忽略,但是jdk5出现的显示的锁,一般这一步不会出错了;
是否有多条语句操作共享语句,解决问题的根本所在了

解决问题的方法:同步代码块,同步方法。前提:多线程,同一把锁

格式: 1synchronized(对象){}        2public synchronized void  方法名(){}

还是卖票吧,只不过我将飘封装称了类,稍微有点不同

1票类:

<span style="white-space:pre">	</span>public class Ticket {
//张数
private int number;
//票价
private float price;
public Ticket(int number) {
this.number=number;
}//get  set省略
2卖票具体线程类:

public class SaleTicke implements Runnable {
private Ticket t;
public SaleTicke(Ticket t) {
this.t = t;
}
@Override
public void run() {
//这个不是共享数据
//int sx=t.getNumber(),并且用sx来判断,各自的栈内存都会有这么一个变量,所以会出现卖200张票
while (true) {
<span style="white-space:pre">			</span>//将所有操作的资源的语句全部用同步代码块包裹
synchronized (this) {
if (t.getNumber() > 0) {
System.out.println(Thread.currentThread().getName()
+ "出售了第" + (t.getNumber()) + "张票");
//卖一张,减少一张,就这里不同
t.setNumber(t.getNumber() - 1);
} else {
break;//run()方法结束,线程结束,jvm结束
}}}}}


3卖票测试类:
<span style="white-space:pre">	</span>public static void main(String[] args) {
Ticket resource =new Ticket(100);
SaleTicke st=new SaleTicke(resource);
Thread t1=new Thread(st,"窗口-1");
Thread t2=new Thread(st,"窗口-2");
t1.start();
t2.start();
}
4卖票总结:当票被封装为类时,第二种安全因素就诞生了,以及在取出值之后要调用set方法来重新设置

5线程间通信:等待唤醒机制,运用jdk5新特性,生产者,消费者

/**
* 资源类
*/
public class Resource {
//资源名
private String name;
//数量
private int count=0;
//标记
private boolean flag=false;
//锁
private Lock lock=new ReentrantLock();
private Condition set=lock.newCondition();

public Resource(){}
//创造资源
public void creatResource() throws InterruptedException{
lock.lock();
try {
//if只判断一次,在这里用不合适
while(flag)//有,等
set.await();
++count;
System.out.println(Thread.currentThread().getName()+"-----生产第"+count+"个商品");
//重置标记
flag=true;
//唤醒
set.signal();
}
finally{
lock.unlock();
}
}
//消费
public void useRes() throws InterruptedException{
lock.lock();
try {
while(!flag)//没有,等
set.await();
System.out.println(Thread.currentThread().getName()+"正在消费第" + count + "商品");
//重置标记
flag=false;
//唤醒
set.signal();
}
finally{
lock.unlock();
}
}
}
/**
* 生产者
*/
public class Creat implements Runnable{
private Resource r=null;
public Creat(Resource r){
this.r=r;
}
public Creat(){
}
@Override
public void run() {
while(true){
try {
r.creatResource();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();}}}
}
/**
* 消费者
*/
public class Use implements Runnable{
private Resource r = null;
public Use(Resource r) {
this.r = r;
}
public Use() {
}
@Override
public void run() {
while(true){try {r.useRes();} catch (InterruptedException e) {e.printStackTrace();}}}}
/**
* 测试类
*/
public class UseTest {
public static void main(String[] args) {
Resource r=new Resource();
Creat c=new Creat(r);
Use u=new Use(r);
new Thread(c,"生产者").start();
new Thread(u,"消费者").start();}
}

结果:
生产者-----生产第26911个商品
消费者正在消费第26911商品
生产者-----生产第26912个商品
消费者正在消费第26912商品
生产者-----生产第26913个商品
消费者正在消费第26913商品
生产者-----生产第26914个商品
消费者正在消费第26914商品
生产者-----生产第26915个商品
消费者正在消费第26915商品
生产者-----生产第26916个商品
消费者正在消费第26916商品
生产者-----生产第26917个商品
消费者正在消费第26917商品
生产者-----生产第26918个商品
消费者正在消费第26918商品
生产者-----生产第26919个商品
消费者正在消费第26919商品
生产者-----生产第26920个商品
消费者正在消费第26920商品

死锁:锁嵌套使用导致

public class DieLock {

public static void main(String[] args) {
new MyThread(true).start();
new MyThread(false).start();
}

}

class Lock {
public static final Object lock1 = new Object();
public static final Object lock2 = new Object();
}

class MyThread extends Thread {
private boolean flag = false;
MyThread(boolean b){
this.flag=b;
}
public void run() {
if (flag) {//锁1嵌套锁2
synchronized (Lock.lock1) {
System.out.println("锁1.....");
synchronized (Lock.lock2) {
System.out.println("锁12..........");
}
}
} else {//锁2嵌套锁1
synchronized (Lock.lock2) {
System.out.println("锁2||||||||");
synchronized (Lock.lock1) {
System.out.println("锁22||||||||||||");
}
}

}
}
}
总结:

1清楚的讲,多线程让我的头大了许多,非常不理解为什么会出错,调试比较难受,啊,真的炸了,最后,一步步分析,判断,找出问题出现的地方并且对症下药才可以;

2那四个判断条件是多么的重要:在写一次

是否是多线程 (是否同时加锁),这个必须是,因为我们编写的就是多线程程序
是否有共享代码,从这一步就要考虑问题的存在了,因为每个线程都有自己的栈内存,程序计数器等
是否是同一把锁,这个往往被忽略,但是jdk5出现的显示的锁,一般这一步不会出错了;
是否有多条语句操作共享语句,解决问题的根本所在了

------- android培训java培训、期待与您交流! ----------
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: