javase--6线程

线程

一、进程与线程的区别

线程是指进程内的一个执行单元,也是进程内的可调度实体.

与进程的区别:
(1)地址空间:进程内的一个执行单元;进程至少有一个线程;它们共享进程的地址空间;而进程有自己独立的地址空间;
(2)资源拥有:进程是资源分配和拥有的单位,同一个进程内的线程共享进程的资源
(3)线程是处理器调度的基本单位,但进程不是.
4)二者均可并发执行.

进程和线程都是由操作系统所体会的程序运行的基本单元,系统利用该基本单元实现系统对应用的并发性。进程和线程的区别在于:

简而言之,一个程序至少有一个进程,一个进程至少有一个线程.
线程的划分尺度小于进程,使得多线程程序的并发性高。
另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。
线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配。这就是进程和线程的重要区别。

进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位.
线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源.
一个线程可以创建和撤销另一个线程;同一个进程中的多个线程之间可以并发执行.

简单的说:多进程:在操作系统中能同时运行多个任务(程序)。多线程:在同一个程序中有多个顺序流执行

二、线程的创建与执行

线程是通过创建java.lang.Thread类的实例来创建的,每个线程有线程体run( )完成操作,通过调用start( )来启动线程

第一种方式:使用Runnable接口创建线程

1.可以将CPU,代码和数据分开,形成清晰的模型

2.线程体run()方法所在的类可以从其它类中继承一些有用的属性和方法

3.有利于保持程序的设计风格一致

第二种方式:直接继承Thread类创建对象

1.Thread子类无法再从其它类继承(java语言单继承)。

2.编写简单,run()方法的当前对象就是线程对象,可直接操作。

在实际应用中,几乎都采取第一种方式
例:

public class TestThread1 {
public static void main(String args[]) {
Runner1 r = new Runner1();
//Thread t = new Thread(r);
//t.start();
r.start();
for(int i=0; i<100; i++) {
System.out.println("main:" + i);
}
}
}
//class Runner1 implements Runnable {
class Runner1 extends Thread {
public void run() {
for(int i=0; i<100; i++) {
System.out.println("Thread 1:" + i);
}
}
}

显示:两个输出相互交替着输出

三、线程的执行

线程的执行:创建-->就绪状态--调度-->运行状态--->终止  ;如果有导致阻塞的事件,进入阻塞状态,阻塞解除,进入就绪状态。

1.sleep( ) throws InterruptedException

调用interrupt( )可抛出该异常

import java.util.Date;


public class TestInterrupt {
public static void main(String args[]) {
Runner2 r = new Runner2();
r.start();
try {
Thread.sleep(10000);//主线程睡眠
} catch(InterruptedException ex) {}
r.interrupt();//线程抛出InterruptedException
}
}
class Runner2 extends Thread{
public void run() {
while(true) {
System.out.println("===="+new Date()+"====");
try {
sleep(1000); //睡眠1s
} catch(InterruptedException ex) {
return;
}
}
}
}

2.join( ) throws InterruptedException

将两个线程合并,一个线程完成后进入第二个线程,相当于方法调用。

public class TestJoin {
public static void main(String args[]) {
Runner3 r = new Runner3("abc");
r.start();
try {
r.join();
} catch(InterruptedException ex) {}
for(int i=0; i<10; i++) {
System.out.println("I am main thread");
}
}
}
class Runner3 extends Thread {
Runner3(String s) {
super(s); //Thread(String s)为线程命名
}
public void run() {
for(int i=0; i<10; i++) {
System.out.println("I am" +getName());
try {
sleep(1000);
} catch(InterruptedException ex) {
return;
}
}
}
}

3.yield( )让出CPU给另一个线程使用,即这个方法后,一定是另一个线程执行

public class TestYield {
public static void main(String args[]) {
Runner4 r1 = new Runner4("r1");
Runner4 r2 = new Runner4("r2");
r1.start();
r2.start();
}
}
class Runner4 extends Thread {
Runner4(String s) {
super(s);
}
public void run() {
for(int i=1; i<=100; i++) {
System.out.println(getName() +":"+i);
if(i % 10 == 0) {
yield();
}
}
}
}

4.setPriority( )与getPriority( )

优先级1-10,Thread.MIN_PRIORITY=1;Thread.MAX_PRIORITY=10;Thread.NORM_PRIORITY=5; 默认为5

public class TestPriority {
public static void main(String args[]) {
Thread r1 = new Thread(new Runner5());
Thread r2 = new Thread(new Runner6());
r1.setPriority(Thread.MAX_PRIORITY);
r2.setPriority(Thread.MIN_PRIORITY);
r1.start();
r2.start();
}
}
class Runner5 implements Runnable {
public void run() {
for(int i=0; i<100; i++) {
System.out.println("r1:"+i);
}
}
}
class Runner6 implements Runnable {
public void run() {
for(int i=0; i<100; i++) {
System.out.println("r2:"+i);
}
}
}

四、同步

1.synchronized

程序在执行的时候,锁定当前对象,有两种方法

public class TestSync implements Runnable{
Timer timer = new Timer();
public static void main(String args[]) {
TestSync test = new TestSync();
Thread t1 = new Thread(test);
Thread t2 = new Thread(test);
t1.setName("t1");
t2.setName("t2");
t1.start();
t2.start();
}
public void run() {
timer.add(Thread.currentThread().getName());
}
}
class Timer {
private static int num = 0;
public synchronized void add(String name) {
//synchronized(this) {
num ++;
try {
Thread.sleep(1);
} catch(InterruptedException ex) {
ex.printStackTrace();
}
System.out.println(name+",你是第"+num+"个使用Timer的线程");
//}
}
}

五、wait( )

只要当类存在同步方法时可以在内部使用wait( ),代表使用该对象的线程被阻隔,而不是对象被阻隔。当线程wait时,所控制的锁不归该线程所有,必须要等到被叫醒后,在等到得到锁之后才能进行后续操作。

对应的叫醒方法为notify( ),意思是叫醒wake在当前对象的一个线程。notifyall( )是叫醒wake在当前对象上的所有线程。

六、生产者和消费者实践

package com.uestc;


public class ProducerConsumer {
public static void main(String args[]) {
SnyStack ss = new SnyStack();
Producer p = new Producer(ss);
Consumer c = new Consumer(ss);
new Thread(p).start();
new Thread(c).start();
}
}
class WoTou {
int id;
public WoTou(int id) {
this.id = id;
}
public String toString() {
return "WoTou-"+id;
}
}
class SnyStack {
int index = 0;
WoTou[] wt = new WoTou[6];
public synchronized void push(WoTou w) {
while(index == wt.length) {//注意,此次,防止因处理InterruptedException继续执行下列代码,使用while,而不是if
try {
this.wait();
} catch(InterruptedException ex) {
ex.printStackTrace();
}
}
this.notify();//叫醒pop
wt[index] = w;
index ++;
}
public synchronized WoTou pop() {
while(index == 0) {
try {
this.wait();
} catch(InterruptedException ex) {
ex.printStackTrace();
}
}
this.notify();
index --;
return wt[index];
}
}
class Producer implements Runnable {
SnyStack ss = null;
public Producer(SnyStack ss) {
this.ss = ss;
}
public void run() {
for(int i=0; i<20; i++) {
WoTou w = new WoTou(i);
ss.push(w);
System.out.println("push: "+w.toString());
try {
Thread.sleep((int)Math.random() * 1000);
} catch(InterruptedException ex) {
ex.printStackTrace();
}
}

}
}
class Consumer implements Runnable {
SnyStack ss = null;
public Consumer(SnyStack ss) {
this.ss = ss;
}
public void run() {
for(int i=0; i<20; i++) {
WoTou w = ss.pop();
System.out.println("pop: "+w.toString());
try {
Thread.sleep((int)Math.random() * 5000);
} catch(InterruptedException ex) {
ex.printStackTrace();
}

}
}
}

猜你喜欢

转载自blog.csdn.net/hx_uestc/article/details/7222898