黑马程序员 Java基础 --->多线程
2013-04-11 14:30
471 查看
----------- android培训、java培训、java学习型技术博客、期待与您交流! ------------
多线程
进程: 是一个正在执行中的程序。每一个进程执行都有一个执行顺序。该顺序是一个执行路径,或者叫一个控制单元。线程: 就是进程中的一个独立的控制单元。线程在控制着进程的执行。一个进程中至少有一个线程。
主线程:Java VM启动的时候会有一个进程java.exe.该进程中至少一个线程负责java程序的执行。而且这个线程运行的代码存在于main方法中。该线程称之为主线程。
1,如何在自定义的代码中,自定义一个线程呢?
通过对api的查找,java已经提供了对线程这类事物的描述。就Thread类。
发现运行结果每一次都不同。
因为多个线程都获取cpu的执行权。cpu执行到谁,谁就运行。明确一点,在某一个时刻,只能有一个程序在运行。(多核除外)cpu在做着快速的切换,以达到看上去是同时运行的效果。我们可以形象把多线程的运行行为在互相抢夺cpu的执行权。这就是多线程的一个特性:随机性。谁抢到谁执行,至于执行多长,cpu说的算。
创建线程的第一种方式:继承Thread类。
步骤:
1,定义类继承Thread。
2,复写Thread类中的run方法。目的:将自定义代码存储在run方法。让线程运行。
3,调用线程的start方法,该方法两个作用:启动线程,调用run方法。
创建线程的第二种方式:实现Runable接口
步骤:
1. 定义类实现Runnable接口
2. 覆盖Runnable接口中的run方法。将线程要运行的代码存放在该run方法中。
3. 通过Thread类建立线程对象。将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数。
4. 为什么要将Runnable接口的子类对象传递给Thread的构造函数。因为,自定义的run方法所属的对象是Runnable接口的子类对象。所以要让线程去指定指定对象的run方法。就必须明确该run方法所属对象。
5. 调用Thread类的start方法开启线程并调用Runnable接口子类的run方法。
实现方式和继承方式有什么区别呢?
实现方式好处:避免了单继承的局限性。
在定义线程时,建立使用实现方式。
两种方式区别:
继承Thread:线程代码存放Thread子类run方法中。
实现Runnable,线程代码存在接口的子类的run方法。
多线线程常用方法:
sleep() 让当前线程睡眠(需要接受一个整数以毫秒计算)
notify() 唤醒第一个被等待的线程
wait() 让当前线程处于等待状态
notifyAll() 唤醒所有的线程
await() 让当前线程处于等待状态
signal() 唤醒第一个被等待的线程
signalAll() 唤醒所有线程
unlock() 释放锁
interrupt() 中断状态:中断冻结状态重新回到运行状态
setDaemon() 将该线程标记为守护线程或用户线程。当正在运行的线程都是守护线程时,Java 虚拟机退出。该方法必须在启动线程前调
join() 当A线程执行到了B线程的.join()方法时,A就会等待。等B线程都执行完,A才会执行。
多线程的运行出现了安全问题。
问题的原因:
当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,另一个线程参与进来执行。导致共享数据的错误。
解决办法:
对多条操作共享数据的语句,只能让一个线程都执行完。在执行过程中,其他线程不可以参与执行。
Java对于多线程的安全问题提供了专业的解决方式。就是同步代码块。
synchronized(对象)
{
需要被同步的代码
}
对象如同锁。持有锁的线程可以在同步中执行。没有持有锁的线程即使获取cpu的执行权,也进不去,因为没有获取锁。
同步的前提:
1,必须要有两个或者两个以上的线程。
2,必须是多个线程使用同一个锁。必须保证同步中只能有一个线程在运行。
好处:解决了多线程的安全问题。
弊端:多个线程需要判断锁,较为消耗资源。
线程同步的两个实例:
实例一:[b]用synchronized来实现同步[/b]
class Demo { public static void main(String[]args) { Resource res = new Resource(); //创建一个Resource类对象 Consumer com = new Consumer(res); //创建一个Consumer类对象,将res存进去 Producer pro = new Producer(res); //创建一个Producer类对象,将res存进去 Thread t1 = new Thread(com); //创建一个线程类对象,将com存进去 Thread t2 = new Thread(com); //创建一个线程类对象,将com存进去 Thread t3 = new Thread(pro); //创建一个线程类对象,将pro存进去 Thread t4 = new Thread(pro); //创建一个线程类对象,将pro存进去 t1.start(); //开启线程 t2.start(); //开启线程 t3.start(); //开启线程 t4.start(); //开启线程 } }
class Resource { private String name; //产品名称 private int count =1; //产品编号 private boolean flag = false; //标记 public synchronized void set(String name) //加上synchronized修饰方法 让该方法同步 { while (flag) //判断标记 { try { wait(); //让当前线程回到等待状态 } catch (Exception e) { } } this.name = name +" "+count++; //把获取到的name和count赋值给成员变量name System.out.println(Thread.currentThread().getName()+"....生产...."+this.name); //打印线程名称和成员变量 flag = true; //更改标记 notifyAll(); //唤醒所有等待线程 } public synchronized void out() //加上synchronized修饰方法 让该方法同步 { while (!flag) //判断标记 { try { wait(); //让当前线程回到等待状态 } catch (Exception e) { } } System.out.println(Thread.currentThread().getName()+"...消费..."+name);//打印线程名称和成员变量 flag = false; //更改标记 notifyAll(); //唤醒所有等待线程 } }
class Producer implements Runnable //继承线程接口 { private Resource res; //定义一个Resource类的引用类型函数 Producer(Resource res) //接收一个存进来的Resource类型对象 { this.res =res; //把成员变量res指向接受进来的对象 } public void run() { while (true) { res.set(" 商品 "); //调用Resource类的set方法 } } }
class Consumer implements Runnable { private Resource res; //定义一个Resource类的引用类型函数 Consumer(Resource res) //接收一个存进来的Resource类型对象 { this.res =res; //把成员变量res指向接受进来的对象 } public void run() { while (true) { res.out(); //调用Resource类的out方法 } } }
实例二:用Lock来实现同步
class Demo { public static void main(String[]args) { Resource res = new Resource(); //创建一个Resource类对象 Consumer com = new Consumer(res); //创建一个Consumer类对象,将res存进去 Producer pro = new Producer(res); //创建一个Producer类对象,将res存进去 Thread t1 = new Thread(com); //创建一个线程类对象,将com存进去 Thread t2 = new Thread(com); //创建一个线程类对象,将com存进去 Thread t3 = new Thread(pro); //创建一个线程类对象,将pro存进去 Thread t4 = new Thread(pro); //创建一个线程类对象,将pro存进去 t1.start(); //开启线程 t2.start(); //开启线程 t3.start(); //开启线程 t4.start(); //开启线程 } }
import java.util.concurrent.locks.*; //导入包 class Resource { private String name; //产品名称 private int count =1; //产品编号 private boolean flag = false; //标记 private Lock lock = new ReentrantLock(); //创建一个锁 private Condition condition_sc = lock.newCondition(); //创建一个Condition对象 private Condition condition_xf = lock.newCondition(); //创建一个Condition对象 public void set(String name) { lock.lock(); //获取锁 try { while (flag) //判断标记 { try { condition_sc.await(); //让当前线程回到等待状态 } catch (Exception e) { } } this.name = name +" "+count++; //把获取到的name和count赋值给成员变量name System.out.println(Thread.currentThread().getName()+"....生产者...."+this.name); //打印线程名称和成员变量 flag = true; //更改标记 condition_xf.signal(); //唤醒线程 } finally { lock.unlock(); //释放锁 } } public void out() { lock.lock(); //获取锁 try { while (!flag) //判断标记 { try { condition_xf.await(); //让当前线程回到等待状态 } catch (Exception e) { } System.out.println(Thread.currentThread().getName()+"...消费者..."+name); //打印线程名称和成员变量 flag = false; //更改标记 condition_sc.signal(); //唤醒线程 } finally { lock.unlock(); //释放锁 } } }
class Producer implements Runnable { private Resource res; //定义一个Resource类的引用类型函数 Producer(Resource res) //接收一个存进来的Resource类型对象 { this.res =res; //把成员变量res指向接受进来的对象 } public void run() { while (true) { res.set(" 商品 "); //调用Resource类的set方法 } } }
class Consumer implements Runnable { private Resource res; //定义一个Resource类的引用类型函数 Consumer(Resource res) //接收一个存进来的Resource类型对象 { this.res =res; //把成员变量res指向接受进来的对象 } public void run() { while (true) { res.out(); //调用Resource类的out方法 } }
----------- android培训、java培训、java学习型技术博客、期待与您交流! ------------
相关文章推荐
- 黑马程序员自学笔记 Java基础<五>---> 多线程
- 黑马程序员 Java基础<五>---> 多线程
- <黑马程序员>---java基础---多线程知识
- 黑马程序员 JAVA基础<三> 多线程
- 黑马程序员 Java基础<七>---> 集合框架
- 黑马程序员 Java基础 ---> 集合(下)
- 黑马程序员 Java基础<一>---> java运行环境搭建
- 黑马程序员——Java基础->多线程
- 黑马程序员 Java基础<三>---> 抽象类、与接口
- 黑马程序员 Java基础 ---> 面向对象(下)
- 黑马程序员 Java基础<九>---> 其他对象
- 黑马程序员 Java基础<一> 数组及排序
- 黑马程序员——java基础知识篇——>java概述
- 黑马程序员——java基础知识篇——>集合
- 黑马程序员 Java基础 --->7K面试题之银行业务调度系统
- 黑马程序员 Java基础<四>---> 异常
- 黑马程序员 Java基础 --->异常处理与包
- 黑马程序员 java基础<二>--其它对象Date、Calendar和Math-Random(2)
- 黑马程序员——java基础知识篇——>反射
- 黑马程序员<java基础<多线程>>