Java Se----多线程

来源:互联网 发布:ssd nvme ubuntu 分区 编辑:程序博客网 时间:2024/04/30 05:44

一、进程:

1. 概念:

I. 程序是静止的概念,而进程是程序的实体,在CPU执行时,才被 赋予生命,只有当程序真正的running时,被称为进程。

II. 在任何时间点、时间戳,只能有一个进程在执行,宏观并行、微观 串行。

二、线程:

1. 概念:

I. 轻量级进程(Light Weight Process LWP),代表进程中一个单一的 顺序控制流程。

II. CPU调用的基本单位是线程(调用某一进程中的某一线程)。

III. 在单个进程中“同时”运行多个线程完成不同的工作,交替执行, 称为多线程。

 

2. 组成:

I. CPU:操作系统分配时间片(Windows5~20msLinux5~800ms)。

II. 数据:堆空间共享(对象),栈空间独立(变量)。

III. 代码:

1). 继承Thread类:

a. 覆盖run方法。

b. 创建子类对象: Thread t1 = new MyExtendsThread();

c. 启动线程: t1.start();

package thread;public class TestBaseThread1 {public static void main(String[] args) {Thread t1 = new MyExtendsThread();//t1.run();//Error 手工调用普通方法t1.start();for (int i = 0; i <= 100; i++) {System.out.println("Main: " + i);}}}class MyExtendsThread extends Thread{@Overridepublic void run() {for (int i = 0; i <= 100; i++) {System.out.println("T1 : " + i);}}}


 

2). 实现Runnable接口:

a. 覆盖run方法。

b. 创建子类对象: Runnable r = new MyImplRunnable();

c. 创建线程对象: Thread t2 = new Thread(r);

d. 启动线程: t2.start();

 

package thread;public class TestBaseThread2 {public static void main(String[] args) {Thread t1 = new MyExtendsThread2();//t1.run();//Error 手工调用普通方法Runnable r= new MyImplRunnable();//定义了真正的running的时候,所需要执行的内容 TaskThread t2 = new Thread(r);t1.start();//启动线程(当t1获取到时间片之后,有JVM调用该线程的run方法)t2.start();}}class MyExtendsThread2 extends Thread{@Overridepublic void run() {for (int i = 0; i <= 100; i++) {System.out.println("T1 : " + i);}}}class MyImplRunnable implements Runnable{@Overridepublic void run() {for (int i = 0; i <= 100; i++) {System.out.println("---T2:" + i);}}}

3). 常用方法:(造成阻塞)

public static void sleep(long millis) //当前线程休眠

public static void yield() //放弃、让出时间片

public final void join() //将其他线程加入到自身线程中,优先执行

 

package thread;public class TestThreadMethod {public static void main(String[] args) {Thread t1 = new MyThread1();Thread t2 = new MyThread2();t1.start();//t2.start();for (int i = 0; i <= 100; i++) {System.out.println("Main:" + i);if(i == 20){try {t1.join();//加入(让t1 线程加入到当前线程中,并优先执行t1)} catch (Exception e) {e.printStackTrace();}}}}}class MyThread1 extends Thread{@Overridepublic void run() {for (int i = 0; i <= 100; i++) {System.out.println("T1 :"+ i );/*if(i == 50){//休眠try {Thread.sleep(200);//当前线程休眠} catch (Exception e) {}}*/}}}class MyThread2 extends Thread{@Overridepublic void run() {for (int i = 0; i <= 100; i++) {System.out.println("---T2:"+ i );/*if(i % 10 == 0){Thread.yield();//放弃、让出时间片}*/}}}

三、线程同步【重点】:

1. 线程不安全:当多线程并发访问临界资源时,如果破坏原子操作,可 能造成数据不一致。

I. 临界资源:共享资源(同一对象)。

II. 原子操作:不可分割的多个步骤,被视为一个整体,其顺序不可打 乱或缺省。

 

2. 互斥锁标记:每个对象都有一个互斥锁标记,用来分配给线程的。

 

3. 锁池:每个对象都有一个锁池,用来存储等待该对象锁标记的线程的

 

4. 同步方式【重点】:

1). 同步代码块:

synchronized(临界资源){ //可为临界资源加锁

//原子操作

}

 

2). 同步方法:

synchronized 返回值类型 方法名称(形参列表){

//原子操作

}

:在调用同步方法时,需要对象的锁标记,而调用非同步方法时, 不需要锁标记,可直接访问。

package synchronize;public class TestSynchronized {public static void main(String[] args) {Account acc = new Account();Husband hus = new  Husband(acc);Wife wife = new Wife(acc);hus.start();wife.start();}}class Account{//账户String cardNo = "622200282789479382793";//卡号String passworld = "123456";//密码Double balance = 2000D;//余额public void take(String no,String pwd , Double money){if(cardNo.equals(no) && passworld.equals(pwd)){System.out.println("登陆成功,请稍后。。。");if(money <= balance){System.out.println("正在处理,请稍后。。。");balance -= money;System.out.println("取款成功,当前余额为"+ balance);}else{System.out.println("卡内余额不足");}}else{System.out.println("账号或密码错误");}}}class Husband extends Thread{//丈夫Account account = null;public Husband(Account account){this.account = account;}@Overridepublic void run() {synchronized (account){//为account对象加锁this.account.take("622200282789479382793", "123456", 1200D);}}}class Wife extends Thread{//妻子Account account = null;public Wife(Account account){this.account = account;}@Overridepublic void run() {synchronized (account){//为account对象加锁this.account.take("622200282789479382793", "123456", 1200D);}}}


四.死锁

一个线程可以同时拥有多个对象的锁标记,当线程阻塞在锁池中时,不会释放已经拥有的锁标记,由此可能造成死锁

 

线程间的通信:等待——通知

              任何对象都有一个等待队列,用来存放线程

T1:o.wait():  必须放在对o加锁的同步代码块中,T1会释放其拥有的所有标记,同时T1会阻塞在o的等待队列中

T2:o.notify()/notifyAll() :必须放在对o加锁的同步代码块中,从o的等待队列中,释放一个/全部 线程

 修饰符组合:

Synchronized static连用:可以连用,给当前类对象加锁

Synchronized abstract连用:不可以

Synchronized 和构造方法连用:不可以

package synchronize;public class TestWaitNotify {public static void main(String[] args) throws Exception {Object o = new Object();Thread t = new SubThread(o);t.start();synchronized(o){System.out.println("Main1");o.wait();System.out.println("Main2");}}}class SubThread extends Thread{Object o;public SubThread(Object o) {this.o = o;}public void run(){synchronized(o){System.out.println("Sub1");o.notifyAll();System.out.println("Sub2");}}}


0 0
原创粉丝点击