黑马程序员——Java多线程
2016-01-29 21:59
537 查看
------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------
进程与线程
进程:是一个正在执行中的程序。每一个进程执行都有一个执行顺序,该顺序是一个执行路径,或者叫一个控制单元。
线程:就是进程中一个独立的控制单元。线程在控制着进程的执行。
一个进程中至少有一个线程。
多线程的运行可以看成是相互争夺cpu的执行权,这就是多线程的一个特征:随机性。谁抢到谁执行,至于执行多长,cpu说的算。
Java VM启动的时候会有一个进程java.exe。
该进程中至少一个线程负责java程序的执行,而且这个线程运行的代码存在于main方法中,该线程称为主线程。
扩展:其实更细节说明java jvm启动不止一个线程,还有负责垃圾回收机制的线程。
如何在自定义的代码中,自定义一个线程呢?
创建线程的两种方式:
继承Thread类
->步骤:
|--定义类继承Thread。
|--复写Thread类中的run方法。目的:将自定义代码存储在run方法,让线程运行。
|--调用线程的start方法。 该方法两个作用:创建线程,调用run方法。
[java] view
plain copy
class Demo extends Thread{
public void run(){
for(int i = 0; i < 60; i++){
System.out.println("demo run----" + i);
}
}
}
public class ThreadDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
Demo d = new Demo();
d.start(); //开启线程并执行该线程的run方法
//d.run(); //仅仅是对象调用方法,而线程创建了,并没有运行
for(int i = 0; i < 60; i++){
System.out.println("hello world----" + i);
}
}
}
实现Runnable接口
->步骤
|--定义类实现接口Runnable接口。
|--覆盖Runnable接口中的run方法。 将线程要运行的代码存放在该run方法中。
|--通过Thread类建立线程对象
|--将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数。
|--调用Thread类的start方法开启线程并调用Runnable接口子类的run方法。
[java] view
plain copy
class RunnableDemo implements Runnable{
private String name;
public RunnableDemo(String name){
this.name = name;
}
public void run() {
// TODO Auto-generated method stub
for(int i = 0; i < 5; i++){
System.out.println(name + ":" + i);
}
}
}
public class TestRunnable {
public static void main(String[] args) {
// TODO Auto-generated method stub
RunnableDemo r1 = new RunnableDemo("tom");
RunnableDemo r2 = new RunnableDemo("jim");
Thread t1 = new Thread(r1);
Thread t2 = new Thread(r2);
t1.start();
t2.start();
}
}
为什么要将Runnable接口的子类对象传递给Thread的构造函数?
自定义的run方法所属的对象是Runnable接口的子类对象,所以要让线程去执行指定对象的run方法,就必须明确该run方法所属对象。
为什么要覆盖run方法?
Thread类用于描述线程。该类定义了一个功能,用于存储线程要运行的代码,该存储功能就是run方法。也就是说Thread类中的run方法,用于存储线程要运行的代码。
线程都有自己默认的名字,通过getName获取线程名称。
实现方式和继承方式有什么区别?
实现方式好处:避免了单继承的局限性。在定义线程时,建立使用实现方式。
两种方式区别:
继承Thread:线程代码存放在Thread子类run方法中。
实现Runnable:线程代码存放在接口的子类的run方法中。
多线程的运行方式导致其容易出现安全问题。
问题产生原因:
当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,另一个线程参与进来执行,导致共享数据的错误。
解决方法:
对多条操作共享数据的语句,只能让一个线程都执行完。在执行过程中,其他线程不能参与执行。
[java] view
plain copy
//java中通过:同步代码块
synchronized(对象)
{
需要同步的代码
}
同步的前提:
1. 必须要有两个或者两个以上的线程。
2. 必须是多个线程使用同一个锁。
3. 必须保证同步中只能有一次线程执行。
优缺点:
解决了多线程的安全问题;多个线程需要判断锁,较为消耗资源。
JDK1.5中提供了多线程升级解决方案。
将同步synchronized替换成现实lock操作,将object中的wait, notifyAll替换成立condition对象,该对象可以lock锁进行获取。
如何停止线程?
只有一种方式,run方法结束。开启多线程运行,运行代码通常都是循环结构,只要控制循环,就可以让run方法结束,也就是线程结束。
特殊情况:
当线程处于冻结状态,就不会读取到标记,那么线程就不会结束。
当没有指定的方式让冻结的线程恢复到运行状态,这时需要对冻结进行清除,强制让线程恢复到运行状态中来,这样就可以操作标记让线程结束。
Thread类提供该方法interrupt();
join:
当A线程执行到了B线程的join()方法时,A就会等待,等B线程执行完,A才会执行。join可以用来临时假死线程执行。
生产者消费者模型(同步代码块实现线程同步):
[java] view
plain copy
public class ProducerConsumer {
public static void main(String[] args) {
// TODO Auto-generated method stub
Resource r = new Resource();
Producer pro = new Producer(r);
Consumer con = new Consumer(r);
Thread t1 = new Thread(pro);
Thread t2 = new Thread(con);
t1.start();
t2.start();
}
}
class Resource{
private String name;
private int count = 1;
private boolean flag = false;
public synchronized void set(String name){
while(flag)
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
this.name = name + "..." + count++;
System.out.println(Thread.currentThread().getName() + "...生产者..." + this.name);
flag = true;
this.notifyAll();
}
public synchronized void out(){
while(!flag)
try{
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "...消费者..." + this.name);
flag = false;
this.notifyAll();
}
}
class Producer implements Runnable{
private Resource res;
Producer(Resource res){
this.res = res;
}
public void run(){
while(true){
res.set("商品");
}
}
}
class Consumer implements Runnable{
private Resource res;
Consumer(Resource res){
this.res = res;
}
public void run(){
while(true){
res.out();
}
}
}
进程与线程
进程:是一个正在执行中的程序。每一个进程执行都有一个执行顺序,该顺序是一个执行路径,或者叫一个控制单元。
线程:就是进程中一个独立的控制单元。线程在控制着进程的执行。
一个进程中至少有一个线程。
多线程的运行可以看成是相互争夺cpu的执行权,这就是多线程的一个特征:随机性。谁抢到谁执行,至于执行多长,cpu说的算。
Java VM启动的时候会有一个进程java.exe。
该进程中至少一个线程负责java程序的执行,而且这个线程运行的代码存在于main方法中,该线程称为主线程。
扩展:其实更细节说明java jvm启动不止一个线程,还有负责垃圾回收机制的线程。
如何在自定义的代码中,自定义一个线程呢?
创建线程的两种方式:
继承Thread类
->步骤:
|--定义类继承Thread。
|--复写Thread类中的run方法。目的:将自定义代码存储在run方法,让线程运行。
|--调用线程的start方法。 该方法两个作用:创建线程,调用run方法。
[java] view
plain copy
class Demo extends Thread{
public void run(){
for(int i = 0; i < 60; i++){
System.out.println("demo run----" + i);
}
}
}
public class ThreadDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
Demo d = new Demo();
d.start(); //开启线程并执行该线程的run方法
//d.run(); //仅仅是对象调用方法,而线程创建了,并没有运行
for(int i = 0; i < 60; i++){
System.out.println("hello world----" + i);
}
}
}
实现Runnable接口
->步骤
|--定义类实现接口Runnable接口。
|--覆盖Runnable接口中的run方法。 将线程要运行的代码存放在该run方法中。
|--通过Thread类建立线程对象
|--将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数。
|--调用Thread类的start方法开启线程并调用Runnable接口子类的run方法。
[java] view
plain copy
class RunnableDemo implements Runnable{
private String name;
public RunnableDemo(String name){
this.name = name;
}
public void run() {
// TODO Auto-generated method stub
for(int i = 0; i < 5; i++){
System.out.println(name + ":" + i);
}
}
}
public class TestRunnable {
public static void main(String[] args) {
// TODO Auto-generated method stub
RunnableDemo r1 = new RunnableDemo("tom");
RunnableDemo r2 = new RunnableDemo("jim");
Thread t1 = new Thread(r1);
Thread t2 = new Thread(r2);
t1.start();
t2.start();
}
}
为什么要将Runnable接口的子类对象传递给Thread的构造函数?
自定义的run方法所属的对象是Runnable接口的子类对象,所以要让线程去执行指定对象的run方法,就必须明确该run方法所属对象。
为什么要覆盖run方法?
Thread类用于描述线程。该类定义了一个功能,用于存储线程要运行的代码,该存储功能就是run方法。也就是说Thread类中的run方法,用于存储线程要运行的代码。
线程都有自己默认的名字,通过getName获取线程名称。
实现方式和继承方式有什么区别?
实现方式好处:避免了单继承的局限性。在定义线程时,建立使用实现方式。
两种方式区别:
继承Thread:线程代码存放在Thread子类run方法中。
实现Runnable:线程代码存放在接口的子类的run方法中。
多线程的运行方式导致其容易出现安全问题。
问题产生原因:
当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,另一个线程参与进来执行,导致共享数据的错误。
解决方法:
对多条操作共享数据的语句,只能让一个线程都执行完。在执行过程中,其他线程不能参与执行。
[java] view
plain copy
//java中通过:同步代码块
synchronized(对象)
{
需要同步的代码
}
同步的前提:
1. 必须要有两个或者两个以上的线程。
2. 必须是多个线程使用同一个锁。
3. 必须保证同步中只能有一次线程执行。
优缺点:
解决了多线程的安全问题;多个线程需要判断锁,较为消耗资源。
JDK1.5中提供了多线程升级解决方案。
将同步synchronized替换成现实lock操作,将object中的wait, notifyAll替换成立condition对象,该对象可以lock锁进行获取。
如何停止线程?
只有一种方式,run方法结束。开启多线程运行,运行代码通常都是循环结构,只要控制循环,就可以让run方法结束,也就是线程结束。
特殊情况:
当线程处于冻结状态,就不会读取到标记,那么线程就不会结束。
当没有指定的方式让冻结的线程恢复到运行状态,这时需要对冻结进行清除,强制让线程恢复到运行状态中来,这样就可以操作标记让线程结束。
Thread类提供该方法interrupt();
join:
当A线程执行到了B线程的join()方法时,A就会等待,等B线程执行完,A才会执行。join可以用来临时假死线程执行。
生产者消费者模型(同步代码块实现线程同步):
[java] view
plain copy
public class ProducerConsumer {
public static void main(String[] args) {
// TODO Auto-generated method stub
Resource r = new Resource();
Producer pro = new Producer(r);
Consumer con = new Consumer(r);
Thread t1 = new Thread(pro);
Thread t2 = new Thread(con);
t1.start();
t2.start();
}
}
class Resource{
private String name;
private int count = 1;
private boolean flag = false;
public synchronized void set(String name){
while(flag)
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
this.name = name + "..." + count++;
System.out.println(Thread.currentThread().getName() + "...生产者..." + this.name);
flag = true;
this.notifyAll();
}
public synchronized void out(){
while(!flag)
try{
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "...消费者..." + this.name);
flag = false;
this.notifyAll();
}
}
class Producer implements Runnable{
private Resource res;
Producer(Resource res){
this.res = res;
}
public void run(){
while(true){
res.set("商品");
}
}
}
class Consumer implements Runnable{
private Resource res;
Consumer(Resource res){
this.res = res;
}
public void run(){
while(true){
res.out();
}
}
}
相关文章推荐
- 黑马程序员——Java泛型
- 程序员就是累死能干的闲死偷懒的
- 程序猿之华丽转身:必备技术面试手册
- Java程序员应当知道的10个面向对象设计原则
- 面试题
- [USACO Dec02]奶牛职业网球赛
- 面试笔试杂项积累-leetcode 26-30
- 曾经的程序员-《30岁的程序员,你迷惘了吗?》
- 20个高级Java面试题汇总
- BTP职业网球赛(二分+并查集)
- iOS iOS面试题及答案
- 面试可以这样谈缺点!
- 《1024伐木累》-程序员妹子与花木兰
- Java程序员在用的大数据工具
- 程序员会不会英语的差别
- 面试笔试杂项积累-leetcode 21-25
- 程序员思考、学习新技术的原则和方式
- 程序员鼓励师到底是个什么东东,猿猿们真的需要吗?
- 程序员的爱情故事续集
- 黑马程序员——接口interface