一、进程与线程的区别:
1.进程有独立的进程空间,进程中的数据存放空间(堆空间和栈空间)是独立的。
2.线程的堆空间是共享的,栈空间是独立的,线程消耗的资源也比进程小,相互之间可以影响的。
二、java中创建多线程的方式:1、继承Thread类;2、实现Runnable接口。
两种进程创建方式比较:
第二种创建多线程的方法:继承Thread类
run()和start()方法的区别:
创建多线程的一种方式,继承Thread类
步骤:
1、定义类并继承自Thread类
2、覆写Thread类中的run()方法
目的:将自定义的代码存储在run()方法中,让线程运行
3、调用现成的start()方法
目的:start()是启动线程用的
package com.blog.source;
public class ThreadDemo extends Thread{
public void run(){
for(int x = 0 ;x <100 ; x++)
System.out.println(Thread.currentThread().getName()+"在运行");
}
public static void main(String[] args) {
new ThreadDemo().start();
new ThreadDemo().start();
new ThreadDemo().start();
}
}
继承Thread类这种实现多线程时,不能在继承其他的java类(因为java只能但集成),相同的资源也不能共享,下面看一下线程的第二种实现方式,实现Runnable接口
第二种创建多线程的方法:实现Runnable接口
步骤:
1、创建类并实现Runnable接口
2、实现Runnable接口中的run方法
3、通过Thread类建立线程对象
4、将Runnable接口的子类作为实际参数传递给Thread的构造方法
为什么要将Runnable接口的子类对象传递给Thread的构造方法?
因为,自定对象所属Runnable接口的子类对象,所以要让线程去
执行指定run方法中的代码,就必须明确该run方法所属对象。
5、调用Thread类中的run方法,并调用Runnable接口中的run方法
package com.blog.source;
public class ThreadDemo implements Runnable{
public void run(){
for(int x = 0 ;x <100 ; x++)
System.out.println(Thread.currentThread().getName()+"在运行");
}
public static void main(String[] args) {
ThreadDemo td = new ThreadDemo();
new Thread(td).start();
new Thread(td).start();
new Thread(td).start();
}
}
实现Runnbale接口和继承Thread类有什么区别?
实现方式,好处是避免了java中单继承的局限性,在实现多线程的时候建议
使用实现方式
继承Thread类:线程代码存放在Thread子类run方法中
实现Runnable:线程代码存放在接口子类的run方法中
三、线程的生命周期:
新建状态,至今尚未启动的线程处于这种状态。
运行状态,正在 Java 虚拟机中执行的线程处于这种状态。
阻塞状态,受阻塞并等待某个监视器锁的线程处于这种状态。
四、控制线程:
控制线程是一件复杂的事情,java给我提供了控制线程的对象:
join方法:调用join方法的线程对象强制运行,该线程强制运行期间,其他线程无法运行,必须等到该线程结束后其他线程才可以运行。
sleep方法:线程休眠: 让执行的线程暂停一段时间,进入阻塞状态。
五、线程安全问题:当多条语句在操作同一数据时,当一个线程只执行了共享数据的一部分时,另外一个线程取得了执行权,修改共享数据。这种情况会导致数据修改错误。解决线程安全问题有三种办法,同步代码块(java中用synchronized关键字同步)、同步方法和静态方法的同步,在jdk1.5之后java引入了同步锁机制。
六、线程之间的通信:
假设现在有一个容器,线程一和线程二都要使用这个容器,线程一使用这个容器的目的是往容器里面放东西,线程二使用这个容器里面取东西,容器里面有东西的时候线程一不能往里面放东西,容器为空的时候线程二不能从容器里面取出东西。此时只有线程一和线程二彼此通信才能知道容器里面是否有东西。
wait():让当前线程放弃监视器进入等待,直到其他线程调用同一个监视器并调用notify()或notifyAll()为止。
notify():唤醒在同一对象监听器中调用wait方法的第一个线程。
notifyAll():唤醒在同一对象监听器中调用wait方法的所有线程。
举例:生产者和消费者
生产者和消费者描述的是这样一个过程:生产者只能生产商品 ,消费者只能使用生产者生产出来的商品。此时,他们都会用到一个共同的区域,就是生产者将生产出来的产品放到这个区域,消费者将该区域内的产品取走 。在过程中会出现如果该区域内没有商品消费者则不能取,如果该区域内有商品生产者不能生产。
Resource.java描述的是生产者和消费者共同使用的资源区域
public class Resource {
/* 创建资源类 */
private String reName;// 产品资源名称
private int count = 0;// 交替生产,目的是为了好区分
/* 如果flag为false时,生产者可以生产,此时消费者不能消费;若falg为ture则不能生产,消费者可以消费 */
private boolean flag = false;
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
public int getCount() {
return count++;
}
public void setCount(int count) {
this.count = count;
}
public String getReName() {
return reName;
}
public void setReName(String reName) {
this.reName = reName;
}
}
Producer.java描述生产者:
public class Producer implements Runnable {
/*创建一个生产者类实现Runnable接口,创建多线程*/
private Resource r = null;
public Producer(Resource r) {
this.r = r;
}
//覆写run方法实现多线程
public void run() {
while (true) { //一直生产
synchronized (r) {
/*如果flag为真则表示产品存放区有产品,此时不能生产产品,所有生产者线程应该休眠等待*/
while (r.isFlag()) {
try {
r.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (r.getCount() == 0) {
r.setReName("苹果");
System.out.println(Thread.currentThread().getName()+ "--生产一个--" + r.getReName());
} else {
r.setReName("梨子");
System.out.println(Thread.currentThread().getName()+ "--生产一个--" + r.getReName());
}
r.setCount(r.getCount() % 2);
/*当前线程创建一个产品之后产品区有了新产品,此时不能进行生产,更改标识flag,并唤醒其他线程*/
r.setFlag(true);
r.notifyAll();
}
}
}
}
Consumer.java描述消费者
<pre name="code" class="java">public class Consumer implements Runnable {
private Resource r = null;
public Consumer(Resource r) {
this.r = r;
}
public void run() {
while (true) {
synchronized (r) {
/*如果flag为真,表示产品区有新产品,此时可以消费,反之则不能消费,所有消费者线程等待*/
while (!r.isFlag()) {
try {
r.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + "--吃掉--"+ r.getReName());
/*当前线程将产品消费掉之后,更改标识,并唤醒其他线程*/
r.setFlag(false);
r.notifyAll();
}
}
}
}
ProducerAndConsumer.java为程序的入口 ,创建多个生产者和多个消费者
public class ProducerAndConsumer {
public static void main(String[] args) {
Resource r = new Resource();
//生产者线程
new Thread(new Producer(r)).start();
new Thread(new Producer(r)).start();
new Thread(new Producer(r)).start();
new Thread(new Producer(r)).start();
//消费者线程
new Thread(new Consumer(r)).start();
new Thread(new Consumer(r)).start();
new Thread(new Consumer(r)).start();
new Thread(new Consumer(r)).start();
}
}
上述代码执行的结果为: