1. 创建线程的两种方式
2. 线程的生命周期
3. 同步的方式
4. 死锁
5. 生产消费模型、监控模型
创建线程的两种方式
结果:
[img]http://dl.iteye.com/upload/attachment/432675/81fc8738-b10d-3c35-8b26-4d6840575541.jpg[/img]
[img]http://dl.iteye.com/upload/attachment/432676/51e0c092-8757-3566-887a-3113febe2f00.jpg[/img]
从图片上我们可以看到,第一张图片数据之间没有实现共享,但是第二张图片,我们可以看到线程1和线程2共享了线程类的实例属性,这是因为程序所创建的Runnable对象只是线程的的target,而多个线程可以共享一个target;
对于用继承Thread和实现Runnable,采用Runnable的话该实现类还可以进行继承,扩展性更强;
启动一个线程用的是start(),而不是run();如果直接用run()则会将它当作一个普通的方法来使用;用start(),则会将run方法当作线程执行体来处理;
前面的两个示例,实际上至少有三条线程,主线程和程序显示创建的两条线程;主线程的线程执行体不是由run方法来确定的,而是由main方法来确定的
线程的生命周期
当程序用new关键字创建一个线程之后,该线程就处于新建状态,此时它和其它Java对象一样,仅仅由Java虚拟机为其分配内存,并初始化了其成员变量的值。当线程调用了start方法后,该线程处于就绪状态;
[img]http://dl.iteye.com/upload/attachment/432679/595f4fa6-e54f-36e9-a37d-1a3f3c6fd452.jpg[/img]
同步的方式
一.synchronized关键字保证同步
锁定方法:表示这个方法同时只能被一个线程访问
锁定对象:表示其限定的代码块只能同时被一个线程访问
二.新用JDK1.5新的同步机制
死锁
当两线程相互等待对方释放同步监视器时就会出现死锁,一旦出现死锁,整个程序既不会发生任何的异常,也不会给出任何的提示,只是所有线程处理阻塞状态,无法继续
生产消费模型、监控模型
2. 线程的生命周期
3. 同步的方式
4. 死锁
5. 生产消费模型、监控模型
创建线程的两种方式
public class Thread1 extends Thread {
private int j;
// 重写run方法
public void run() {
for (; j < 100; j++) {
System.out.println(getName() + " " + j);
}
}
// 主函数
public static void main(String args[]) {
for (int i = 0; i < 100; i++) {
// 打印主线程执行信息
System.out.println(Thread.currentThread().getName() + " " + i);
if (i == 20) {
// 新启两个线程
new Thread1().start();
new Thread1().start();
}
}
}
}
public class Thread2 implements Runnable {
private int j;
// 实现run方法
public void run() {
for (; j < 100; j++) {
System.out.println(Thread.currentThread().getName() + " " + j);
}
}
// 主方法
public static void main(String args[]) {
for (int i = 0; i < 100; i++) {
// 打印主线程执行信息
System.out.println(Thread.currentThread().getName() + " " + i);
if (i == 20) {
// 新启两个线程
Thread2 thread=new Thread2();
new Thread(thread,"新线程1").start();
new Thread(thread,"新线程2").start();
}
}
}
}
结果:
[img]http://dl.iteye.com/upload/attachment/432675/81fc8738-b10d-3c35-8b26-4d6840575541.jpg[/img]
[img]http://dl.iteye.com/upload/attachment/432676/51e0c092-8757-3566-887a-3113febe2f00.jpg[/img]
从图片上我们可以看到,第一张图片数据之间没有实现共享,但是第二张图片,我们可以看到线程1和线程2共享了线程类的实例属性,这是因为程序所创建的Runnable对象只是线程的的target,而多个线程可以共享一个target;
对于用继承Thread和实现Runnable,采用Runnable的话该实现类还可以进行继承,扩展性更强;
启动一个线程用的是start(),而不是run();如果直接用run()则会将它当作一个普通的方法来使用;用start(),则会将run方法当作线程执行体来处理;
前面的两个示例,实际上至少有三条线程,主线程和程序显示创建的两条线程;主线程的线程执行体不是由run方法来确定的,而是由main方法来确定的
线程的生命周期
当程序用new关键字创建一个线程之后,该线程就处于新建状态,此时它和其它Java对象一样,仅仅由Java虚拟机为其分配内存,并初始化了其成员变量的值。当线程调用了start方法后,该线程处于就绪状态;
[img]http://dl.iteye.com/upload/attachment/432679/595f4fa6-e54f-36e9-a37d-1a3f3c6fd452.jpg[/img]
同步的方式
一.synchronized关键字保证同步
锁定方法:表示这个方法同时只能被一个线程访问
//同步方法 同步监视器为this
public synchronized int getM1(int count){
return 1;
}
锁定对象:表示其限定的代码块只能同时被一个线程访问
//同步代码块
public void getM2(){
synchronized(obj){
//代码块,obj为同步监视器
}
}
二.新用JDK1.5新的同步机制
private Lock lock=new ReentrantLock();
//在方法内使用同步锁
public void getM3(){
//开始锁
lock.lock();
//同步区。。。
try{
}finally{
//释放锁
lock.unlock();
}
}
死锁
当两线程相互等待对方释放同步监视器时就会出现死锁,一旦出现死锁,整个程序既不会发生任何的异常,也不会给出任何的提示,只是所有线程处理阻塞状态,无法继续
class A {
synchronized void foo(B b) {
String name = Thread.currentThread().getName();
System.out.println(name + " entered A.foo");
try {
Thread.sleep(1000);
} catch (Exception e) {
System.out.println("A Interrupted");
}
System.out.println(name + " trying to call B.last()");
// 因为b对象被锁住了,调用b内的方法时,在等锁的释放
b.last();
}
synchronized void last() {
System.out.println("Inside A.last");
}
}
class B {
synchronized void bar(A a) {
String name = Thread.currentThread().getName();
System.out.println(name + " entered B.bar");
try {
Thread.sleep(1000);
} catch (Exception e) {
System.out.println("B Interrupted");
}
System.out.println(name + " trying to call A.last()");
// 因为a对象被锁住了,调用a内的方法时,在等锁的释放
a.last();
}
synchronized void last() {
System.out.println("Inside A.last");
}
}
class Deadlock implements Runnable {
A a = new A();
B b = new B();
Deadlock() {
Thread.currentThread().setName("MainThread");
Thread t = new Thread(this, "RacingThread");
t.start();
a.foo(b); // 同步监视器为a
System.out.println("Back in main thread");
}
public void run() {
b.bar(a); // 同步监视器为b
System.out.println("Back in other thread");
}
public static void main(String args[]) {
new Deadlock();
}
}
生产消费模型、监控模型
//生产消费模型
public class Main {
public static void main(String args[]) {
List<Egg> list = new ArrayList<Egg>();
new Product(list).start();
new Customer(list).start();
}
}public class Egg {
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String toString() {
return id + " " + name;
}
}public class Product extends Thread {
private List<Egg> list;
private int count;
public Product(List<Egg> list) {
this.list = list;
}
// 重写run方法
public void run() {
System.out.println("生产线程启动");
while (true) {
try {
Thread.sleep(100);
synchronized (list) {
//还有鸡蛋时
while (list.size() > 0) {
list.wait();
}
//没有鸡蛋时
while(list.size()==0){
Egg egg=new Egg();
egg.setId(count++);
egg.setName("鸡蛋");
System.out.println("生产线程生产"+egg.toString());
list.add(egg);
//通知消费线程
list.notify();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}public class Customer extends Thread {
private List<Egg> list;
public Customer(List<Egg> list) {
this.list = list;
}
// 重写run方法
public void run() {
System.out.println("消费线程启动");
while (true) {
try {
Thread.sleep(100);
synchronized (list) {
//没有则等待
while (list.size() == 0) {
list.wait();
}
//有鸡蛋时
while(list.size()>0){
System.out.println("消费线程消费"+list.remove(0).toString());
//通知生产线程
list.notify();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
//监控模型public class Control implements Runnable {
// 存放统计线程的队列
private static List<CountFile> list = new ArrayList<CountFile>();
// 主函数
public static void main(String args[]) {
// 取得系统的根目录个数
java.io.File[] dirF = java.io.File.listRoots();
// 根据目录创建统计纯种个数
for (int i = 0; i < dirF.length; i++) {
CountFile cf = new CountFile(dirF[i].getAbsolutePath());
cf.start();
list.add(cf);
}
System.out.println(dirF.length + " 个统计线程已启动");
// 启动监视线程
new Thread(new Control()).start();
System.out.println("监视线程已启动");
}
// 实现run方法
public void run() {
boolean flag = true;
String result = "";
while (flag) {
for (int i = 0; i < list.size(); i++) {
if (list.get(i).isFinished()) {
// 取得统计结果
result += list.get(i).getResult();
// 移出统计完的线程
list.remove(i);
}
}
// 全部统计完
if (list.isEmpty()) {
flag = false;
}
try {
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
}
System.out.println("统计结果如下:");
System.out.println(result);
}
}public class CountFile extends Thread {
private String root;// 进行搜索的根目录的名字
private int lengthCount;// 所有文件长度
private int dirCount;// 目录数
private int realFileCount;// 统计的真正文件数量
private boolean finished = false;
// 构造时传入搜索根目录名
public CountFile(String root) {
this.root = root;
}
/**
* 查看线程是否统计结束
*
* @return
*/
public boolean isFinished() {
return finished;
}
/**
* 返回统计结果
*
* @return
*/
public String getResult() {
StringBuffer result = new StringBuffer();
result.append(root + "盘统计结果如下:\r\n");
result.append(" 文件数量: " + realFileCount);
result.append(" 目录数: " + dirCount);
result.append(" 文件总长度(单位K): " + lengthCount / 1204);
result.append("\r\n");
return result.toString();
}
// 重写run方法
public void run() {
long start = System.currentTimeMillis();
lengthCount = countProcess(root);
long cost = System.currentTimeMillis() - start;
finished = true;
}
/**
* 统计目录下文件的长度
*
* @param root
* 要统计的目录
* @return 目录下文件的长度
*/
private int countProcess(String root) {
int count = 0;
File dirFile = new File(root);
// 目录不存在
if (!dirFile.exists()) {
return count;
}
// 获得目录下的所有文件组成的数组
File[] subFile = dirFile.listFiles();
if (subFile == null) {
return count;
}
// 对这个数组进行遍历
for (int i = 0; i < subFile.length; i++) {
// 是个目录
if (subFile[i].isDirectory()) {
dirCount++;
count += countProcess(subFile[i].getAbsolutePath());// 用递归计算该目录下的文件长度
}
// 是一个文件
if (subFile[i].isFile()) {
realFileCount++;
count += subFile[i].length();
}
}
return count;
}
}