多线程

进程:当一个程序进入内存运行,即变成一个进程

(单核计算机在同一个时间点上,游戏进程和音乐进程是同时在运行吗?不是,因为计算机的CPU只能在某个时间点上做一件事。由于计算机将在游戏进程和音乐进程之间频繁的执行,切换速度极高,人类感觉游戏和音乐在同时进行。(一个大脑)多进程并发其实是2核和4核的计算机,(2个和4个大脑)

多进程的作用不是提高执行速度,而是提高CPU的使用类

多线程不是为了提高执行速度,而是提高程序的使用率。可以给现实世界中的人类一种错觉,感觉多个线程在同时并发执行。

线程和线程共享“堆内存和方法区内存”,栈内存是独立的,一个线程一个栈。(重要)

进程和进程之间的内存是独立的。

线程线程是进程中的一个执行单元。负责当前进程中程序的执行。简而言之:一个程序运行后至少有一个进程,一个进程中可以包含多个线程。

多线程:即一个程序中有多个线程在同时执行。

举例:单线程程序:即去网吧,一个人下机下一人上机。多线程程序:网吧能够让多个人同时上网。

java程序的运行原理?

java命令会启动java虚拟机,启动JVM,等于启动了一个应用程序,表示启动了一个进程,该进程会自动启动一个“主线程”,然后主线程去调用某个类的main方法。所以main方法运行在主线程中。


程序运行原理:

分时调度:所有线程轮流使用CPU的使用权,平均分配每个线程占用CPU的时间。

抢占式调度:优先让优先级高的线程使用CPU,如果线程的优先级相同,那么会随机选择一个(线程随机性),java使用的为抢占式调度。(正确理解为优先级高的线程获取的CPU时间片多一点)

抢占式调度详解:QQ,迅雷同时在运行,感觉这些软件好像在同一时刻运行着。实际上,CPU(中央处理器)使用抢占式模式在多个线程间进行着高速的切换,对于CPU的一个核而言,某个时刻,只能执行一个线程,而CPU在多个线程间切换速度相对我们的感觉要快,看上去就是在同一时刻运行。其实,多线程程序并不能提高程序的运行速度,但能够提高程序运行效率。让CPU的使用率更高。

在java语言中实现多线程的第一种方式:

第一步:继承java.lang.Thread;

第二步:重写run方法.

三个知识点:

如何定义线程?

如何创建线程?

如何启动线程?

*/

public class ThreadTest02

{

public static void main(String[] args){

//创建线程

Thread t = new Processor();

//启动

t.start(); //这段代码执行瞬间结束。告诉JVM再分配一个新的栈给t线程.

//run不需要程序员手动调用,系统线程启动之后自动调用run方法.

//t.run(); //这是普通方法调用,这样做程序只有一个线程,run方法结束之后,下面程序才能继续执行。

//这段代码在主线程中运行.

for(int i=0;i<10;i++){

System.out.println("main-->" + i);

}

//有了多线程之后,main方法结束只是主线程栈中没有方法栈帧了。

//但是其他线程或者其他栈中还有栈帧。

//main方法结束,程序可能还在运行。

}

}

//定义一个线程

class Processor extends Thread

{

//重写run方法

public void run(){

for(int i=0;i<30;i++){

System.out.println("run-->" + i);

}

}

}

java中实现线程的第二种方式:

第一步:写一个类实现java.lang.Runnable;接口

第二步:实现run方法.

public class ThreadTest03

{

public static void main(String[] args){

//创建线程

Thread(Runnable target)构造方法

Thread t =new Thread(Runable);创建线程其实底层是这个方法

Thread t = new Thread(new Processor());

//启动

t.start();

}

}

//这种方式是推荐的。因为一个类实现接口之外保留了类的继承。

class Processor implements Runnable

{

public void run(){

for(int i=0;i<10;i++){

System.out.println("run-->"+i);

}

}

}

线程的生命周期?

线程生命周期结构图

线程新建之后调用start方法进入就绪状态,就绪状态的线程表示有权力去获取CPU的时间片,拿到CPU的时间片进入运行状态,运行执行run方法,时间片用完后再回去到就绪状态,等待拿到CPU时间片,拿到CPU时间片再去运行run方法,反复如此,直到run方法执行完毕,这个线程就消亡。运行时候会出现线程阻塞,线程阻塞后等待线程解除阻塞,解除阻塞后,进入就绪状态

CPU时间片:是执行权,当线程拿到CPU时间片之后就马上执行run方法,这个时候就带白哦进入了运行状态。

新建:采用new语句创建完成

就绪:执行start后

运行:占用CPU时间

阻塞:执行了wait语句,执行了sleep语句和等待某个对象锁,等待输入的场合

终止:退出run()方法

2.线程的调度与控制

通常我们的计算机只有一个CPU,CPU在某一个时刻职能执行一条指令,线程只有得到CPU时间片,也就是使用权,才可以执行命令,在单CPU的机器上线程不是并行运行的,只有在多个CPU上线程才可以并行运行,java虚拟机要负责线程的调度,取得CPU的使用权,目前有两种调度模型:分时调度模型和抢占式调度模型,java使用抢占式的调度模型。

分时调度模型:所有线程轮流使用CPU的使用权,平均分配每个线程占用cpu的时间片

抢占式调度模型:优先让优先级高的线程使用CPU,如果线程的优先级相同,那么会随机选择一个,优先级高的线程获取的CPU时间片相对多一些。

2.1.线程的优先级

线程的优先级主要分三种:max_priority(最高级10); min_priority(最低级1) norm_priority(标准5)默认(优先级一般是1--10)

1.获取当前线程对象Thread.currentThread();

2.给线程起名 t.setName("t1");

3.获取线程的名字 t.getName();

线程优先级高的获取的CPU时间片相对多一些。

优先级:1-10。//设置优先级   t1.setPriority(5);

System.out.println(Thread.NORM_PRIORITY); //5

1.Thread.sleep(毫秒);

2.sleep方法是一个静态方法.

3.该方法的作用:阻塞当前线程.腾出CPU,让给其他线程。

public class ThreadTest06

{

public static void main(String[] args) throws InterruptedException{

//Thread.currentThread(); //t保存的内存地址指向的线程是“主线程对象”

Thread t1 = new Processor();

t1.setName("t1");

t1.start();

//阻塞主线程

for(int i=0;i<10;i++){

System.out.println(Thread.currentThread().getName()+"--->"+i);

Thread.sleep(500);

}

}

}

class Processor extends Thread

{

//Thread中的run方法不抛出异常,所以重写run方法之后,在run方法的声明位置上不能使用throws

//所以run方法中的异常只能try...catch...

public void run(){

for(int i=0;i<10;i++){

//Thread.currentThread(); //t保存的内存地址指向的线程是“t1线程对象”

System.out.println(Thread.currentThread().getName()+"--->"+i);

try{

Thread.sleep(1000); //让当前线程阻塞1S。

}catch(InterruptedException e){

e.printStackTrace();

}

}

// m1();

}

//m1方法是可以使用throws的.

public void m1() throws Exception{

}

面试题:考点其实是对象也能调用静态方法()

//静态的方法按照正规的方式访问:“类名.”  //静态的方法也能用“引用.”访问  st.m2(); //编译阶段检查出st是StaticTest03类型,编译通过,运行的时候,仍然使用 "StaticTest03."的方式访问。//该方法执行不需要对象。//空的引用去访问成员的时候会出现空指针异常。//m2方法不是“成员”而是静态的。//所以即使引用是空的,也不会报空指针异常。(其实也就是说,m2 方法执行底层是 不需要这个对象的。)

public class ThreadTest07{

public static void main(String[] args) throws Exception{

//创建线程

Thread t = new Processor();

t.setName("t");

//启动线程

t.start();

//休眠

t.sleep(5000); //等同于Thread.sleep(5000); 阻塞的还是当前线程,和t线程无关。

System.out.println("HelloWorld!");

A a = null;

a.m1(); //不会出现空指针异常。}

}

class Processor extends Thread

{

public void run(){

for(int i=0;i<200;i++){

System.out.println(Thread.currentThread().getName()+"------->"+i);

} } }

class A{

public static void m1(){} }

yield 让位,它与sleep()类似,只是不能由用户指定暂停多长时间,并且yield()方法只能让同优先级的线程有执行的机会。

某线程正在休眠,如果打断它的休眠.

以下方式依靠的是异常处理机制。//打断t的休眠.t.interrupt();

3.线程同步锁机制

t1和t2

异步编程模型:t1线程执行t1的,t2线程执行t2的,两个线程之间谁也不等谁。

同步编程模型:t1线程和t2线程执行,当t1线程必须等t2线程执行结束之后,t1线程才能执行,这是同步编程模型。

什么时候要同步呢?为什么要引入线程同步呢?

1.为了数据的安全。尽管应用程序的使用率降低,但是为了保证数据是安全的,必须加入线程同步机制。

线程同步机制使程序变成了(等同)单线程。

2.什么条件下要使用线程同步?

第一:必须是多线程环境

第二:多线程环境共享同一个数据.

第三:共享的数据涉及到修改操作。

以下程序演示取款例子。以下程序不使用线程同步机制,多线程

同时对同一个账户进行取款操作,会出现什么问题?

使用线程同步机制保证数据的安全。

public class ThreadTest12

{

public static void main(String[] args){

//创建一个公共的账户

Account act = new Account("actno-001",5000.0);

//创建线程对同一个账户取款

Thread t1 = new Thread(new Processor(act));

Thread t2 = new Thread(new Processor(act));

t1.start();

t2.start();

}}

//取款线程

class Processor implements Runnable

{

//账户

Account act; //成员变量账户

//Constructor提供构造方法

Processor(Account act){

this.act = act;

}

public void run(){

act.withdraw(1000.0);

System.out.println("取款1000.0成功,余额:" + act.getBalance());

}

}

//账户

class Account

{

private String actno; // 账户

private double balance; 余额

public Account(){}

public Account(String actno,double balance){

this.actno = actno;

this.balance = balance;

}

//setter and getter

public void setActno(String actno){

this.actno = actno;

}

public void setBalance(double balance){

this.balance = balance;

}

public String getActno(){

return actno;

}

public double getBalance(){

return balance;

}

//对外提供一个取款的方法

public void withdraw(double money){ //对当前账户进行取款操作

double after = balance - money;

//延迟

try{Thread.sleep(1000);}catch(Exception e){}

//更新

this.setBalance(after);

}

}

//对外提供一个取款的方法

public void withdraw(double money){ //对当前账户进行取款操作


原理:t1线程和t2线程.

t1线程执行到此处,遇到了synchronized关键字,就会去找this的对象锁,

如果找到this对象锁,则进入同步语句块中执行程序。当同步语句块中的代码

执行结束之后,t1线程归还this的对象锁。

在t1线程执行同步语句块的过程中,如果t2线程也过来执行以下代码,也遇到

synchronized关键字,所以也去找this的对象锁,但是该对象锁被t1线程持有,

只能在这等待this对象的归还。

//把需要同步的代码,放到同步语句块中. this就是共享对象this就是账户

synchronized(this){

double after = balance - money;

//延迟

try{Thread.sleep(1000);}catch(Exception e){}

//更新

this.setBalance(after);

}}}

总结:线程执行代码,遇到了synchronized关键字,就会去这个对象的对象锁,找到则执行,找不到则等待。再看它是不是共享同一个数据

//synchronized关键字添加到成员方法上,线程拿走的也是this的对象锁。

public synchronized void withdraw(double money){ //对当前账户进行取款操作

double after = balance - money;

//延迟

try{Thread.sleep(1000);}catch(Exception e){}

//更新

this.setBalance(after);

}

}

这样的使用方式也可以,比第一种范围大了。根据需求使用






































最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,948评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,371评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,490评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,521评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,627评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,842评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,997评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,741评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,203评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,534评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,673评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,339评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,955评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,770评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,000评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,394评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,562评论 2 349

推荐阅读更多精彩内容

  • 本文主要讲了java中多线程的使用方法、线程同步、线程数据传递、线程状态及相应的一些线程函数用法、概述等。 首先讲...
    李欣阳阅读 2,444评论 1 15
  • Java多线程学习 [-] 一扩展javalangThread类 二实现javalangRunnable接口 三T...
    影驰阅读 2,952评论 1 18
  • 一、线程的生命周期 线程状态转换图: 1、新建状态 用new关键字和Thread类或其子类建立一个线程对象后,该线...
    我是嘻哈大哥阅读 893评论 0 8
  • 知识点:一. 什么是线程: 进程是指运行中的应用程序,每一个进程都有自己独立的内存空间。一个应用程序可以同时启动多...
    木有鱼丸啦阅读 645评论 0 0
  • 早在一百多年前,托尔斯泰就说过:“幸福的家庭都是相似的;不幸的家庭各有各的不幸。” 以此类推,我们可以得出这样的结...
    罗掌柜real阅读 464评论 0 0