并发-----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票类:
3卖票测试类:
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 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培训、期待与您交流! ----------
多线程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培训、期待与您交流! ----------
相关文章推荐
- 反射生成java类
- OOP----java面向对象理解
- Struts2 格式化日期、时间和数字
- Java关键字break和continue
- 关于SpringMVC相关配置文件
- Java基础知识强化之IO流笔记03:throws的方式处理异常
- Java编写猜数字小游戏
- Java IO 之 InputStream源码
- 将java项目改成web项目
- JAVA Pattern和Matcher 的用法
- 使用junit单元测试SpringMvc
- Spring3 MVC请求参数获取的几种方法
- Struts对MVC的实现流程
- Java中异常处理之try和catch代码块的使用
- Spring之FactoryBean .
- Java Util 验证身份证号码是否规范
- Java实现把cmyk格式图片转换为RGB格式图片
- 利用java监听器实现在线人数统计
- eclipse下Ctrl+H搜索并替换全项目字符串
- MyEclipse项目中的包层次视图