多线程总结
进程和线程的区别
1、进程是资源分配最小单位,线程是程序执行的最小单位;
2、进程有自己独立的地址空间,每启动一个进程,系统都会为其分配地址空间,建立数据表来维护代码段、堆栈段和数据段,线程没有独立的地址空间,它使用相同的地址空间共享数据;
3、CPU切换一个线程比切换进程花费小;
4、创建一个线程比进程开销小;
5、线程占用的资源要⽐进程少很多。
6、线程之间通信更方便,同一个进程下,线程共享全局变量,静态变量等数据,进程之间的通信需要以通信的方式(IPC)进行;(但多线程程序处理好同步与互斥是个难点)
7、多进程程序更安全,生命力更强,一个进程死掉不会对另一个进程造成影响(源于有独立的地址空间),多线程程序更不易维护,一个线程死掉,整个进程就死掉了(因为共享地址空间);
8、进程对资源保护要求高,开销大,效率相对较低,线程资源保护要求不高,但开销小,效率高,可频繁切换;
创建线程的两种方法
继承Thread类
实例代码(开发一个线程类,该类的构造方法参数是线程名称,该线程的功能是从1打印到1000。)
public class A {
public void go() {
for(int i=0;i<=1000;i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
public class One extends Thread{
public One(String name) {
super(name);
}
@Override
public void run() {
for(int i=0;i<=1000;i++) {
System.out.println(this.getName()+":"+i);
}
}
}
public class Two extends A implements Runnable {
@Override
public void run() {
this.go();
}
}
public class Main {
public static void main(String[] args) {
Thread t0 = Thread.currentThread();
Thread t1 =new One("A");
t1.start();
Thread t2 =new Thread (new Two(),"B");
t2.start();
for(int i=1;i<=1000;i++) {
System.out.println(t0.getName()+":"+i);
try {
Thread.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println(t0.getName()+"结束");
}
}
实现Runnable接口
实例代码(二、开发一个功能类(该类未继承Thread类),该类有一个公有实例方法,功能为从201打印到300;再实现一个线程,该线程的父类是功能类,该线程的功能通过调用父类的功能方法实现。)
public class A extends Thread{
public A(String name) {
super(name);
}
@Override
public void run() {
for(int i=1;i<=100;i++) {
System.out.println(this.getName()+":"+i);
// try {
// Thread.sleep(10);
// } catch (InterruptedException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
}
}
}
public class B extends GongNeng implements Runnable {
private Thread t0;
B(Thread t0){
this.t0=t0;
}
@Override
public void run() {
this.go(t0);
}
}
public class GongNeng {
public void go(Thread t) {
for(int i=201;i<=300;i++) {
// try {
// Thread.sleep(10);
// } catch (InterruptedException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
System.out.println(Thread.currentThread().getName()+":"+i);
if(i==220) {
try {
t.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
public class Test {
public static void main(String[] args) {
Thread t0 =new A("A");
Thread t1 =new Thread(new B(t0),"B");
t0.start();
t1.start();
}
}
线程同步
实例
public class PrintString {
private static Object lock =new Object();
private String str;
public PrintString(String str) {
super();
this.str = str;
}
public void pr() {
synchronized (lock) {
for(int i=0;i<str.length();i++) {
System.out.println(Thread.currentThread().getName()+":"+str.charAt(i));
try {
Thread.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
public class Test {
public static void main(String[] args) {
PrintString p1 =new PrintString("hello!大家好!");
PrintString p2 =new PrintString("hello!祝大家中秋节快乐!");
new Thread("线程1:") {
@Override
public void run() {
p1.pr();
}
}.start();
new Thread("线程2:") {
@Override
public void run() {
p2.pr();
}
}.start();
}
}
线程协作
实例
代码
public class MB {
private int size;
private int maxSize;
public MB( int maxSize) {
this.maxSize = maxSize;
}
public synchronized void chan() {
while(this.isFull()) {
try {
System.out.println(Thread.currentThread().getName()+"面包库已经存储满了!请停止生产*********************");
this.wait();
System.out.println(Thread.currentThread().getName()+"被唤醒了##############");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
size++;
System.out.println(Thread.currentThread().getName()+"生产了一块面包,现在面包数量为:"+size);
this.notifyAll();
Thread.yield();
}
public synchronized void mai() {
while(this.isEmpty()) {
try {
System.out.println(Thread.currentThread().getName()+"面包已经卖完啦!请等待**********************");
this.wait();
System.out.println(Thread.currentThread().getName()+"被唤醒了###############");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
size--;
System.out.println(Thread.currentThread().getName()+"卖了一块面包,现在面包数量为:"+size);
this.notifyAll();
Thread.yield();
}
public boolean isEmpty() {
return size==0;
}
public boolean isFull() {
return size==maxSize;
}
}
public class Test {
public static void main(String[] args) {
MB m =new MB(5);
for (int i = 0; i < 100; i++) {
new Thread("生产厂家:") {
public void run() {
for (int j = 0; j < 20; j++) {
m.chan();
}
};
}.start();
new Thread("消费者:") {
public void run() {
for (int j = 0; j <20; j++) {
m.mai();
}
};
}.start();
}
}
}
线程中常用的方法
1、线程部分方法详解
2、线程启动
3、守护线程
4、线程同步的概念
5、线程的同步互斥
6、线程协作
7、实现线程同步的方法有哪些
同步代码块
同步实例方法
同步类方法(静态方法)
8、sleep()方法和wait()方法的区别
一.查看API
sleep是Thread类的方法,导致此线程暂停执行指定时间,给其他线程执行机会,但是依然保持着监控状态,过了指定时间会自动恢复,调用sleep方法不会释放锁对象。
wait方法是Object类里的方法,当一个线程执行到wait()方法时,它就进入到一个和该对象相关的等待池中,同时释放了锁对象,等待期间可以调用里面的同步方法,其他线程可以访问,等待时不拥有CPU的执行权,否则其他线程无法获取执行权。
二.是否可以传入参数
sleep()方法必须传入参数,参数就是休眠时间,时间到了就会自动醒来。
wait()方法可以传入参数也可以不传入参数,传入参数就是在参数结束的时间后开始等待,不穿如参数就是直接等待。
三.是否需要捕获异常
sleep方法必须要捕获异常,而wait方法不需要捕获异常。
四.作用范围
wait、notify和notifyAll方法只能在同步方法或者同步代码块中使用,而sleep方法可以在任何地方使用。
五.是否释放锁
sleep方法继续持有锁,
wait方法则释放锁