您的位置:首页 > 职场人生

黑马程序员-java多线程

2013-09-28 23:01 323 查看
------- android培训java培训、期待与您交流! ----------

1 进程与线程

进程是程序的一次动态执行过程,是系统进行资源分配和调度的一个独立单位。

线程是进程执行过程中产生的执行线索,是比进程单位更小的执行单位。

2 单线程与多线程

· 单线程的程序只有一个顺序执行流,只能依次向下执行每行代码,当某行代码遇到阻塞就会停滞不前。

多线程的程序有多条顺序执行流,当某的线程在阻塞状态时,别的线程会抢占cpu资源来运行,多线程抢占执行权是随机性的。

3 线程的创建

线程的创建必须要通过Thread类,有两种方式,可以是自定义类来继承Thread类,也可以是自定义类来实现Runnable接口。

1 通过继承Thread类创建线程

步骤:1 定义类继承Thread类

2 重写Thread类的run方法

3 调用线程的start方法来启动线程

例子

package thread;
class ThreadDemo extends Thread { // 线程的主体类
@Override
public void run() { // 线程的主方法
System.out.println("通过继承Thread类方式");//输出
}
}
public class Test {
public static void main(String[] args) throws Exception {
ThreadDemo td = new ThreadDemo() ;//新建线程对象
td.start() ;//调用start()启动线程
}
}


2 通过实现Runnable接口创建线程

步骤:1 定义类实现Runnable接口

2 重写Runnable接口的run方法

3 声明并初始化实现Runnable接口子类对象

4 声明Thread类对象,将实现Runnable接口对象作为实参来实例化Thread类对象

5 调用Thread类对象的start方法启动线程

例子

class RunnableDemo implements Runnable { // 线程的主体类
@Override
public void run() { // 线程的主方法
System.out.println("通过实现Runnable接口方式");//输出
}
}
public class Test {
public static void main(String[] args) throws Exception {
RunnableDemo rd = new RunnableDemo() ;//新建实现Runnable接口对象
Thread t = new Thread(rd); //声明并初始化Thread类对象,把事项Runnable接口对象作为实参
t.start() ;//调用start()启动线程
}
}


4 实现Runnable方法比继承Thread常用原因

1 Runnable方式避免了Thread类方式单继承的局限性,可以继承其他类

2 Runnable方式可以使多个线程共享同一个资源文件

5 线程的生命周期

1 New :新建状态,当用new创建一个线程,就处于新建状态

2 Runnable :就绪状态,当调用start方法,就处于就绪状态,但此时,并一定开始运行了,只是表示可以有运行资源,还要JVM里线程调度器的调度

3 Running:运行状态,执行线程体

4 Blocked:阻塞状态,是指暂停线程的执行以等待某个条件的发生

5 dead:死亡状态,线程结束就处于死亡状态。

6 Lock:锁定状态,同步加锁,在对共享资源的访问机制

6 线程状态转化图



7 控制线程方法

1 void join():等待该线程终止

当执行流调用其他线程的join方法,调用线程将被阻塞,直到join线程完成为止

范例

class RunnableDemo implements Runnable { // 线程的主体类
@Override
public void run() { // 线程的主方法
for(int i=0;i<5;i++){
System.out.println(Thread.currentThread().getName() + "--->" + i);
}
}
}

public class Test {
public static void main(String[] args) throws Exception {
RunnableDemo rd = new RunnableDemo() ;//新建实现Runnable接口对象
Thread t1 = new Thread(rd,"线程1"); //声明并初始化Thread类对象,把事项Runnable接口对象作为实参
t1.start() ;//调用start()启动线程
for(int i=0;i<5;i++){
System.out.println(Thread.currentThread().getName() + "--->" + i);
if(i==2){
t1.join(); //调用join方法,main主线程执行到i==5时,主线程进入阻塞状态,此时只有t1线程执行,直到t1执行完,才再次进入就绪状态
}
}
}
}

输出结果
main--->0
main--->1
main--->2
线程1--->0
线程1--->1
线程1--->2
线程1--->3
线程1--->4
main--->3
main--->4


2 void setDaemon(boolean on):将该线程标记为守护线程或用户线程

也称为后台线程,当前台所有线程死亡时,被设置为后台线程随之死亡

3 static void sleep(long millis):在指定的毫秒数内让当前正在执行的线程休眠(暂停执行)

范例

class RunnableDemo implements Runnable { // 线程的主体类
@Override
public void run() { // 线程的主方法
for(int i=0;i<5000000;i++){
try {
Thread.sleep(10);
} catch (Exception e) {}
System.out.println(Thread.currentThread().getName() + "--->" + i);
}
}
}

public class Test {
public static void main(String[] args) throws Exception {

RunnableDemo rd = new RunnableDemo() ;//新建实现Runnable接口对象
Thread t1 = new Thread(rd,"线程1"); //声明并初始化Thread类对象,把事项Runnable接口对象作为实参
t1.setDaemon(true); //设置为后台线程
t1.start() ;//调用start()启动线程
for(int i=0;i<5;i++){
System.out.println(Thread.currentThread().getName() + "--->" + i);
}
//当for循环执行后,程序就结束
}
}
输出结果
main--->0
main--->1
main--->2
main--->3
main--->4
线程1--->0
线程1--->1


class RunnableDemo implements Runnable { // 线程的主体类
@Override
public void run() { // 线程的主方法
for(int i=0;i<5000000;i++){
try {
Thread.sleep(10);
} catch (Exception e) {}
System.out.println(Thread.currentThread().getName() + "--->" + i);
}
}
}

public class Test {
public static void main(String[] args) throws Exception {

RunnableDemo rd = new RunnableDemo() ;//新建实现Runnable接口对象
Thread t1 = new Thread(rd,"线程1"); //声明并初始化Thread类对象,把事项Runnable接口对象作为实参
t1.setDaemon(true); //设置为后台线程
t1.start() ;//调用start()启动线程
for(int i=0;i<5;i++){
System.out.println(Thread.currentThread().getName() + "--->" + i);
}
//当for循环执行后,程序就结束
}
}
输出结果
main--->0
main--->1
main--->2
main--->3
main--->4
线程1--->0
线程1--->1


4 static void yield():暂停当前正在执行的线程对象,并执行其他对象

只是放弃了执行权,但还是在就绪状态,当再次抢到执行权,还是可以继续执行的

5 void setPriority(int newPriority):更改线程的优先级

参数为:Thread.MAX_PRIORITY 最高优先级,10级

Thread.MIN_PRIORITY 最低优先级,1级

Thread.NORM_PRIORITY 默认优先级,5级

范例

class RunnableDemo implements Runnable { // 线程的主体类
@Override
public void run() { // 线程的主方法
for(int i=0;i<5;i++){
try {
Thread.sleep(10);
} catch (Exception e) {}
System.out.println(Thread.currentThread().getName() + "--->" + i);
if(i==3){
Thread.yield();
}
}
}
}

public class Test {
public static void main(String[] args) throws Exception {

RunnableDemo rd = new RunnableDemo() ;//新建实现Runnable接口对象
Thread t1 = new Thread(rd,"高级线程1"); //声明并初始化Thread类对象,把事项Runnable接口对象作为实参
Thread t2 = new Thread(rd,"低级线程2"); //声明并初始化Thread类对象,把事项Runnable接口对象作为实参
t1.setPriority(Thread.MAX_PRIORITY); //设置该线程优先级为最高
t2.setPriority(Thread.MIN_PRIORITY); //设置该线程优先级为最低
t1.start() ;//调用start()启动线程
t2.start() ;//调用start()启动线程
}
}

输出结果
高级线程1--->0
低级线程2--->0
高级线程1--->1
低级线程2--->1
高级线程1--->2
低级线程2--->2
高级线程1--->3
低级线程2--->3
低级线程2--->4
高级线程1--->4


8 线程同步

线程同步是指当多个线程操作同一个资源时因为延迟之类问题引起信息安全问题

实现线程同步方式:

1 同步代码块

在代码块上加上“synchronized“关键字,格式如下:

synchronized (同步对象){

......//需要同步的代码



2 同步方法

使用”synchronized“关键字将一个方法声明成同步方法,格式如下:

synchronized 方法返回值 方法名称(参数列表){}

当没有实现线程同步代码可能出现的问题卖票范例:

class MyThread implements Runnable{			// 实现Runnable接口
private int ticket = 5 ;				// 一共5张票
public void run(){				// 覆写run()方法
for(int i=0;i<10;i++){			// 超出票数的循环
if(ticket>0){			// 判断是否有剩余票
try {
Thread.sleep(100) ;	// 加入延迟
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("卖票:ticket = " + ticket--) ;
}
}
}
};
public class Test {
public static void main(String[] args) {
MyThread mt = new MyThread() ;		// 定义线程对象
Thread t1 = new Thread(mt) ;			// 定义Thread对象
Thread t2 = new Thread(mt) ;			// 定义Thread对象
Thread t3 = new Thread(mt) ;			// 定义Thread对象
t1.start() ;				// 启动线程
t2.start() ;				// 启动线程
t3.start() ;				// 启动线程
}

}
输出结果
卖票:ticket = 5
卖票:ticket = 4
卖票:ticket = 3
卖票:ticket = 2
卖票:ticket = 1
卖票:ticket = 0
卖票:ticket = -1


使用同步代码块的卖票范例:

class MyThread implements Runnable{		// 实现Runnable接口
private int ticket = 5 ;			// 一共5张票
public void run(){				// 覆写run()方法
for(int i=0;i<10;i++){			// 超出票数的循环
synchronized (this) {		// 设置需要同步的操作
if(ticket>0){		// 判断是否有剩余票
try {
Thread.sleep(100) ;	// 加入延迟
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("卖票:ticket = " + ticket--) ;
}
}
}
}
};

public class Test {
public static void main(String[] args) {
MyThread mt = new MyThread() ;		// 定义线程对象
Thread t1 = new Thread(mt) ;			// 定义Thread对象
Thread t2 = new Thread(mt) ;			// 定义Thread对象
Thread t3 = new Thread(mt) ;			// 定义Thread对象
t1.start() ;				// 启动线程
t2.start() ;				// 启动线程
t3.start() ;				// 启动线程
}

}
输出结果
卖票:ticket = 5
卖票:ticket = 4
卖票:ticket = 3
卖票:ticket = 2
卖票:ticket = 1


使用同步方法的卖票范例:

class MyThread implements Runnable{		// 实现Runnable接口
private int ticket = 5 ; // 一共5张票
public void run(){ // 覆写run()方法
for(int i=0;i<100;i++){ // 超出票数的循环
this.sale(); // 调用同步方法
}
}
public synchronized void sale() { // 声明同步方法
if(ticket>0){ // 判断是否有剩余票
try {
Thread.sleep(300) ; // 加入延迟
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("卖票:ticket = " + ticket--) ;
}
}
};
public class Test {
public static void main(String[] args) {
MyThread mt = new MyThread() ; // 定义线程对象
Thread t1 = new Thread(mt) ; // 定义Thread对象
Thread t2 = new Thread(mt) ; // 定义Thread对象
Thread t3 = new Thread(mt) ; // 定义Thread对象
t1.start() ; // 启动线程
t2.start() ; // 启动线程
t3.start() ; // 启动线程
}
} 输出结果 卖票:ticket = 5 卖票:ticket = 4 卖票:ticket = 3 卖票:ticket = 2 卖票:ticket = 1


9 同步锁

从JDK1.5后,java提供了同步锁的线程同步机制,锁提供了共享资源的独占访问,每次只能有一个线程对Lock对象加锁,线程方为人共享资源之前先获得Lock对象,然后Lock对象调用lock()方法加锁,执行代码,最后调用unlock()方法解锁。

格式如下:

class X {
private final ReentrantLock lock = new ReentrantLock(); //定义锁对象

//定义需要保证线程安全的方法
public void m(){
lock.lock();
try{
//需要保证线程安全的代码
}finally{
lock.unlock();
}
}

}


10 死锁

当两个线程相互等待对方释放同步监视器是就会发生死锁,当发生死锁,所有线程处于阻塞状态,无法继续执行

死锁范例:

class Zhangsan{
public void say(){
System.out.println("张三对李四说:“先付钱,再收货。”");
}
public void get(){
System.out.println("张三得到钱了。");
}
}
class Lisi{
public void say(){
System.out.println("李四对张三说:“先收货,再付款。”");
}
public void get(){
System.out.println("李四得到货了。");
}
}
public class Test implements Runnable{
private static Zhangsan zs = new Zhangsan();
private static Lisi ls = new Lisi();
private boolean flag = false;
public void run(){
if(flag){
synchronized (zs) {
zs.say();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (ls) {
zs.get();
}
}
}else{
synchronized (ls) {
ls.say();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (zs) {
ls.get();
}
}
}
}
public static void main(String[] args) {
Test d1 = new Test();
Test d2 = new Test();
d1.flag = true;
d2.flag = false;
new Thread(d1).start();
new Thread(d2).start();

}
}
输出结果
张三对李四说:“先付钱,再收货。”
李四对张三说:“先收货,再付款。”


11 线程通信

当线程在运行是,线程的调度具有一定的随机性和透明性,程序通常无法准确控制线程的轮换执行,但是可以通过一些机制俩保证线程协调运行

1 可以借助Object类提供的wait(),notify()和notifyAll()三个方法

wait():让当前线程放弃监视器进入等待,直到其他线程调用同一个监视器并调用notify()或notifyAll()为止。

notify():唤醒在同一对象监听器中调用wait方法的第一个线程。

notifyAll():唤醒在同一对象监听器中调用wait方法的所有线程。

2 可以通过同步锁机制Lock类提供的awit(),signal()和signalAll()方法

await(): 等价于同步监听器的wait()方法;

signal(): 等价于同步监听器的notify()方法;

signalAll(): 等价于同步监听器的notifyAll()方法;

生产者和消费者范例:

class Info{
private String name = "张三";
private String content = "学生";
private boolean flag = false;
public synchronized void set(String name,String content){
if(!flag){
try {
super.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.setName(name);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.setContent(content);
flag = false;
super.notify();
}
public synchronized void get(){
if(flag){
try {
super.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
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;
}
public void run(){
boolean flag = false;
for(int i=0;i<50;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;
}
public void run(){
for(int i=0;i<50;i++){
this.info.get();
}
}
}
public class Test {
public static void main(String[] args) {
Info info = new Info();
Producer p = new Producer(info);
Consumer c = new Consumer(info);
new Thread(p).start();
new Thread(c).start();
}

}
输出结果
张三--->学生
李四--->老师
张三--->学生
李四--->老师
张三--->学生
李四--->老师
张三--->学生
李四--->老师


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