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

java的线程问题同步与互斥

2014-08-07 23:21 387 查看
以前学过java的线程,但是当时对Tread的理解不是很深,对于里面的同步与互斥,生产者与消费者问题,理解的不够深入,这次又从新学习java的多线程,感觉对线程的理解更加的深入了,觉得有必要写下博客记录下。

本文原创,转载请著明:http://blog.csdn.net/j903829182/article/details/38420503

1.java实现线程的方法;

   1.实现Runnable接口,重写run方法,通过Thread的start方法启动线程。这种方法可以实现资源的共享

   2.继承Thread类,重写run方法

   推荐使用Runnable接口实现多线程。

2.线程的状态

   创建

   开始

   就绪

   运行

   阻塞

   终止

3.线程控制的基本方法

  isAlive判断线程是否还活着,即线程是否还未终止

  getPriority获得线程的优先级数,数值。

  setPriority设置线程的优先级数值

  Thread.sleep将当前线程睡眠指定毫秒数

  join调用某线程的该方法,将当前线程与该线程“合并”,即等待该线程结束,再恢复当前线程的运行。

  yield让出cpu,当前线程进入就绪等待调度

  wait当前线程进入对象的wait pool

  notify/notifyAll唤醒对象的wait pool中的一个/所有等待线程

4.wait和sleep的区别

   wait时别的线程可以访问锁定对象,释放cpu的控制权,调用wait方法时必须锁定该对象

   sleep时别的线程也不可以访问锁定对象。但可以释放cpu的控制权

5.在执行wait()和notify()之前,必须要先获得互斥锁,即一定要和synchronized一起使用

6.需要注意的是notify()/notifyAll()(唤醒在等待该对象同步锁的线程)调用后,并不是马上就释放对象锁的,

  而是在相应的synchronized(){}语句块执行结束,自动释放锁后,JVM才会在wait()对象锁的线程中随机选取一线程,

  赋予其对象锁,唤醒线程,继续执行。

7.以下是我写的线程的一些例子,相信应该能够看懂,我就不多说了,有不理解的可以相互交流,共同进步。

生产者消费者的例子:

package com.wj.demo;
/*
class Info{
private String name="李新华";
private String content="java讲师";
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}

}

class Producer implements Runnable{

private Info info=null;
public Producer(Info info){
this.info=info;
}
@Override
public void run() {
// TODO Auto-generated method stub
boolean flag=false;
for(int i=0;i<50;i++){
if(flag){
this.info.setName("李兴华");
try {
Thread.sleep(90);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
this.info.setContent("java讲师");
flag=false;
}else{
this.info.setName("baidu");
try {
Thread.sleep(90);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
this.info.setContent("www.baidu.com");
flag=true;
}
}
}

}

class Consumer implements Runnable{

private Info info=null;
public Consumer(Info info){
this.info=info;
}

@Override
public void run() {
// TODO Auto-generated method stub
for(int i=0;i<50;i++){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

System.out.println(this.info.getName()+"--->"
+this.info.getContent());
}
}

}

*/

/*
class Info{
private String name="李新华";
private String content="java讲师";

public synchronized void set(String name,String content){
this.setName(name);
try {
Thread.sleep(300);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
this.setContent(content);
}

public synchronized void get(){
try {
Thread.sleep(300);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

System.out.println(this.getName()+"-->"
+this.getContent());

}

public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}

}

class Producer implements Runnable{

private Info info=null;
public Producer(Info info){
this.info=info;
}
@Override
public void run() {
// TODO Auto-generated method stub
boolean flag=false;
for(int i=0;i<50;i++){
if(flag){
this.info.set("李兴华","java讲师");
flag=false;
}else{
this.info.set("mldn", "www.mldn.com");
flag=true;
}
}
}

}

class Consumer implements Runnable{

private Info info=null;
public Consumer(Info info){
this.info=info;
}

@Override
public void run() {
// TODO Auto-generated method stub
for(int i=0;i<50;i++){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

this.info.get();
}
}

}

*/

/*
class Info{
private String name="李新华";
private String content="java讲师";
private boolean flag=false;

public synchronized void set(String name,String content){

if(!flag){
try {
super.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
this.setName(name);
try {
Thread.sleep(300);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

this.setContent(content);
flag=false;
super.notify();
}

public synchronized void get(){
if(flag){
try {
super.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

try {
Thread.sleep(300);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(this.getName()+"-->"
+this.getContent());
flag=true;
super.notify();

}

public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}

}

class Producer implements Runnable{

private Info info=null;
public Producer(Info info){
this.info=info;
}
@Override
public void run() {
// TODO Auto-generated method stub
boolean flag=false;
for(int i=0;i<50;i++){
if(flag){
this.info.set("李兴华","java讲师");
flag=false;
}else{
this.info.set("mldn", "www.mldn.com");
flag=true;
}
}
}

}

class Consumer implements Runnable{

private Info info=null;
public Consumer(Info info){
this.info=info;
}

@Override
public void run() {
// TODO Auto-generated method stub
for(int i=0;i<50;i++){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

this.info.get();
}
}

}
*/

class Info{
private String name="张三";
//private String content="java讲师";
private boolean flag=false;

public synchronized void set(String name){

if(!flag){
try {
super.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
this.setName(name);
try {
Thread.sleep(300);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

//this.setContent(content);

flag=false;
super.notify();
}

public synchronized void get(){
if(flag){
try {
super.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

try {
Thread.sleep(300);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

System.out.println(this.getName()+"-->"
);
flag=true;
super.notify();

}

public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
/*public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}*/

}

class Producer implements Runnable{

private Info info=null;
public Producer(Info info){
this.info=info;
}
@Override
public void run() {
// TODO Auto-generated method stub
boolean flag=false;
for(int i=0;i<20;i++){
if(flag){
this.info.set("张三");
flag=false;
}else{
this.info.set("李四");
flag=true;
}
}
}

}

class Consumer implements Runnable{

private Info info=null;
public Consumer(Info info){
this.info=info;
}

@Override
public void run() {
// TODO Auto-generated method stub
for(int i=0;i<20;i++){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

this.info.get();
}
}

}

public class ThreadDemo2 {

/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub

Info i=new Info();
Producer pro=new Producer(i);
Consumer con=new Consumer(i);
new Thread(pro).start();
new Thread(con).start();
}

}


下面是程序的输出结果:
张三-->

李四-->

张三-->

李四-->

张三-->

李四-->

张三-->

李四-->

张三-->

李四-->

张三-->

李四-->

张三-->

李四-->

张三-->

李四-->

张三-->

李四-->

张三-->

李四-->

从运行结果可以看到的是,生产者生产一个,消费者消费一个,进行同步输出

下面是我的写的一个买票的线程例子:

package com.wj.demo;

class MyThread1 extends Thread{
private String name;
public MyThread1(String name){
this.name=name;
}
@Override
public void run() {
// TODO Auto-generated method stub
for(int i=0;i<10;i++){
System.out.println(name+i);
}
}

}

class MyThread2 implements Runnable{

private String name;
public MyThread2(String name){
this.name=name;
}
@Override
public void run() {
// TODO Auto-generated method stub
for(int i=0;i<10;i++){
System.out.println(name+i);
}
}

}

class MyThread3 implements Runnable{

private int ticket=5;

@Override
public void run() {
// TODO Auto-generated method stub
if(ticket>0){
System.out.println("卖票:ticket="+ticket--);
}
}

}

class MyThread4 implements Runnable{

@Override
public void run() {
// TODO Auto-generated method stub
for(int i=0;i<3;i++){
System.out.println(Thread.currentThread().getName()+"运行,i="+i);
}

}

}

class MyThread5 implements Runnable{

private String name;
private int time;
public MyThread5(String name,int time){
this.name=name;
this.time=time;
}
@Override
public void run() {
// TODO Auto-generated method stub
try {
Thread.sleep(this.time);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(this.name+"线程,休眠"+this.time+"毫秒");

}

}

class MyThread6 implements Runnable{

private int ticket=110;
/*private String name=null;
public MyThread6(String name){
this.name=name;
}*/
@Override
public void run() {
// TODO Auto-generated method stub
for(int i=0;i<200;i++){
synchronized(this){
if(ticket>0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"卖票:ticket="+ticket--);
}
}
}
}

}

public class ThreadDemo1 {

/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
//MyThread1 mt1=new MyThread1("线程A");
//MyThread1 mt2=new MyThread1("线程B");
//mt1.start();
//mt2.start();
/*
MyThread2 my1=new MyThread2("线程--A");
MyThread2 my2=new MyThread2("线程--B");
Thread th1=new Thread(my1);
Thread th2=new Thread(my2);
th1.start();
th2.start();*/
/*
MyThread3 my=new MyThread3();
new Thread(my).start();
new Thread(my).start();
new Thread(my).start();
new Thread(my).start();
new Thread(my).start();*/

/*
MyThread4 my=new MyThread4();
new Thread(my).start();
new Thread(my,"线程A").start();
new Thread(my,"线程B").start();
new Thread(my).start();
new Thread(my).start();*/

/*
MyThread5 my1=new MyThread5("线程A",10000);
MyThread5 my2=new MyThread5("线程B",20000);
MyThread5 my3=new MyThread5("线程C",30000);
MyThread5 my4=new MyThread5("线程D",40000);
new Thread(my1).start();
new Thread(my2).start();
new Thread(my3).start();
new Thread(my4).start();*/

MyThread6 mt=new MyThread6();
Thread t1=new Thread(mt,"A");
Thread t2=new Thread(mt,"B");
Thread t3=new Thread(mt,"C");
Thread t4=new Thread(mt,"D");
Thread t5=new Thread(mt,"E");
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();

}

}


程序的运行结果可能如下所示:

B卖票:ticket=110

B卖票:ticket=109

B卖票:ticket=108

B卖票:ticket=107

B卖票:ticket=106

B卖票:ticket=105

B卖票:ticket=104

B卖票:ticket=103

B卖票:ticket=102

B卖票:ticket=101

B卖票:ticket=100

B卖票:ticket=99

E卖票:ticket=98

E卖票:ticket=97

E卖票:ticket=96

E卖票:ticket=95

E卖票:ticket=94

E卖票:ticket=93

E卖票:ticket=92

E卖票:ticket=91

E卖票:ticket=90

E卖票:ticket=89

E卖票:ticket=88

E卖票:ticket=87

E卖票:ticket=86

E卖票:ticket=85

E卖票:ticket=84

E卖票:ticket=83

E卖票:ticket=82

E卖票:ticket=81

E卖票:ticket=80

E卖票:ticket=79

E卖票:ticket=78

E卖票:ticket=77

E卖票:ticket=76

D卖票:ticket=75

D卖票:ticket=74

D卖票:ticket=73

D卖票:ticket=72

C卖票:ticket=71

C卖票:ticket=70

C卖票:ticket=69

C卖票:ticket=68

C卖票:ticket=67

C卖票:ticket=66

C卖票:ticket=65

A卖票:ticket=64

A卖票:ticket=63

A卖票:ticket=62

C卖票:ticket=61

C卖票:ticket=60

C卖票:ticket=59

C卖票:ticket=58

C卖票:ticket=57

C卖票:ticket=56

C卖票:ticket=55

C卖票:ticket=54

C卖票:ticket=53

C卖票:ticket=52

C卖票:ticket=51

C卖票:ticket=50

D卖票:ticket=49

D卖票:ticket=48

D卖票:ticket=47

D卖票:ticket=46

D卖票:ticket=45

D卖票:ticket=44

D卖票:ticket=43

D卖票:ticket=42

D卖票:ticket=41

E卖票:ticket=40

E卖票:ticket=39

E卖票:ticket=38

E卖票:ticket=37

E卖票:ticket=36

E卖票:ticket=35

E卖票:ticket=34

E卖票:ticket=33

E卖票:ticket=32

E卖票:ticket=31

E卖票:ticket=30

E卖票:ticket=29

B卖票:ticket=28

B卖票:ticket=27

B卖票:ticket=26

B卖票:ticket=25

B卖票:ticket=24

B卖票:ticket=23

B卖票:ticket=22

B卖票:ticket=21

B卖票:ticket=20

B卖票:ticket=19

B卖票:ticket=18

B卖票:ticket=17

B卖票:ticket=16

B卖票:ticket=15

B卖票:ticket=14

E卖票:ticket=13

E卖票:ticket=12

D卖票:ticket=11

D卖票:ticket=10

D卖票:ticket=9

D卖票:ticket=8

D卖票:ticket=7

D卖票:ticket=6

D卖票:ticket=5

C卖票:ticket=4

C卖票:ticket=3

C卖票:ticket=2

C卖票:ticket=1

下面的程序展示的是,打印10次A,10次B,10次C,打印的顺序是ABCABCABC.......下面是用线程实现的代码。

代码里面的注释已经很清楚了,我就不再解释了,有问题的,欢迎一起交流,一起进步。

package com.wj.demo;
/*
* 1.Product类是一个产品类,用来表示生产产品
* 2.里面的有set和get方法,set方法用来设置生产什么样的产品,get是得到产品*/
class Product{
private String name="A";//产品的名字
private boolean flag=true;//标志,true代表可以生产,false代表可以取得产品
//注意:super.wait(),super.notifyAll()这2个方法,一定要是在synchronized所
//包含的代码块里面调用,也就是说只有拥有对象锁的线程,才能有权调用super.wait(),super.notifyAll()
//方法,否则会出错。之所以会这样,是因为super.wait()方法是把拥有该对象锁的线程放到等待该对象锁的队列中进行休息
//这个过程需要找到拥有对象锁的线程,所以super.wait()方法应该在synchronized里面的代码块中调用;
//同理,super.notifyAll()是用来唤醒在等待该对象锁队列中所有的线程,所以也需要和对象锁有关系,唤醒的是想得到
//该对象锁的所有线程,因此也需要在synchronized代码块中使用。
//synchronized表示只有拥有该对象锁的线程才能进入synchronized代码块,里面。
//综上所述,synchronized,super.wait(),super.notifyAll(),在进行同步控制的时候一般是需要一起配对使用
public synchronized void getName() {//得到产品的函数
if(flag){//如果标志为true,则代表只可以生产,不能进行取产品
try {
super.wait();//调用Object父类的方法,使得到该对象锁的线程等待,把该线程放到等待该对象锁的队列里面
//,并且释放cpu,和释放该对象的对象锁,使其他的线程可以得到该对象的锁
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

System.out.println(name);//打印产品的名字
try {
Thread.sleep(200);//该线程休眠200毫秒,释放cup,让其他的线程执行,但是不会释放对象锁
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
flag=true;//把标志置位true,表示已经取了产品了,可以进行生产了,已经不没有产品了,不能得到产品了
//调用了super.notifyAll()方法后,并不会马上执行,要等待synchronized代码块所有的程序执行完了以后才会
//释放对象锁,进行唤醒其他的线程
super.notifyAll();//调用父类Object的方法,释放对象锁,唤醒在等待该对象锁的所有线程
}

public synchronized void setName(String name) {
if(!flag){//如果flag为false则表示,只可以取产品,不能进行生产产品
try {
super.wait();//进行等待,和上面的一样
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

try {
Thread.sleep(200);//解释如上
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

this.name = name;//设置产品的名字
flag=false;//设置标志,表示可以取产品了,不能再进行生产了
super.notifyAll();//如上所示,唤醒其他的想得到该对象锁的所有线程
}

}

//Factory类是一个工厂,用来控制生产什么样的产品
class Factory implements Runnable{
private Product product;//共享的对象

public Factory(Product product) {//构造函数,对product进行初始化
super();
this.product = product;
}

@Override
public void run() {//覆写的run方法,进行线程操作
// TODO Auto-generated method stub
for(int i=1;i<31;i++){
if(i%3==1){//如果余数为1,则生产A产品
product.setName("A");//生产A产品
}else if(i%3==2){//如果余数为2,则生产B产品
product.setName("B");//生产B产品
}else{//其他的生产C产品
product.setName("C");//生产C产品
}
}
}

}

//Customer是消费者类,用来使用工厂生产的产品
class Customer implements Runnable{
private Product product;//贡献资源对象

public Customer(Product product) {//构造函数,初始化product
super();
this.product = product;
}

@Override
public void run() {
// TODO Auto-generated method stub
for(int i=1;i<31;i++){
try {
Thread.sleep(500);//进行线程休眠,使打印有时间延迟
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.print(""+i+"----->");
this.product.getName();//消费产品

}
}

}

public class ThreadDemo4 {

/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Product p=new Product();//创建共享资源对象
Factory fp=new Factory(p);//创建工厂
Customer cp=new Customer(p);//创建消费者
Thread tfp=new Thread(fp);//创建工厂线程进行生产
Thread tcp=new Thread(cp);//创建消费者线程进行消费
tfp.start();//启动线程
tcp.start();//启动线程
}

}


程序的运行结果如下:
1----->A

2----->B

3----->C

4----->A

5----->B

6----->C

7----->A

8----->B

9----->C

10----->A

11----->B

12----->C

13----->A

14----->B

15----->C

16----->A

17----->B

18----->C

19----->A

20----->B

21----->C

22----->A

23----->B

24----->C

25----->A

26----->B

27----->C

28----->A

29----->B

30----->C

到此线程的知识也就基本讲完了,发现对上面的知识进行总结以后,线程也就并没有那么难了,难得就是难于理解什么是多线程,多线程的运行过程。要是理解了多线程的运行过程,那么java中的线程也就没那么可怕了。最后一点就是要举义反三,融汇贯通,利用典型的生产者消费者模式,可以演变后解决很多线程的问题。希望好好理解生产者消费者模式。如果对线程还有什么问题,希望我们可以一起交流。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息