当前位置:文档之家› Java线程及多线程技术及应用

Java线程及多线程技术及应用

Java线程及多线程技术及应用
Java线程及多线程技术及应用

第6 章 Java线程及多线程技术及应用6.1线程基本概念

1、进程和线程的基础知识

●进程:运行中的应用程序称为进程,拥有系统资源(cpu、内存)

●线程:进程中的一段代码,一个进程中可以哦有多段代码。本身不拥有资源(共享

所在进程的资源)

在java中,程序入口被自动创建为主线程,在主线程中可以创建多个子线程。

区别:1、是否占有资源问题

2、创建或撤销一个进程所需要的开销比创建或撤销一个线程所需要的开销大。

3、进程为重量级组件,线程为轻量级组件

●多进程: 在操作系统中能同时运行多个任务(程序)

●多线程: 在同一应用程序中有多个功能流同时执行

2、线程的主要特点

●不能以一个文件名的方式独立存在在磁盘中;

●不能单独执行,只有在进程启动后才可启动;

●线程可以共享进程相同的内存(代码与数据)。

3、线程的主要用途

●利用它可以完成重复性的工作(如实现动画、声音等的播放)。

●从事一次性较费时的初始化工作(如网络连接、声音数据文件的加载)。

●并发执行的运行效果(一个进程多个线程)以实现更复杂的功能

4、多线程(多个线程同时运行)程序的主要优点

●可以减轻系统性能方面的瓶颈,因为可以并行操作;

●提高CPU的处理器的效率,在多线程中,通过优先级管理,可以使重要的程序优先

操作,提高了任务管理的灵活性;另一方面,在多CPU系统中,可以把不同的线程

在不同的CPU中执行,真正做到同时处理多任务。

6.2 线程创建与启动

1、与线程编程有关的一些概念

创建方式: 1 继承https://www.doczj.com/doc/f92514824.html,ng.Thread类 2 实现https://www.doczj.com/doc/f92514824.html,ng.Runnable接口

线程体:public void run()方法,其内的程序代码决定了线程的行为和功能。

线程启动:public void start () , 线程启动后,需要获取cpu才能自动调用run()运行。线程休眠:public void sleep(long ms), 线程将暂停,放弃cpu

2、利用继承Thread类创建线程的示例

package com.px1987.j2se.thread.base;

/**通过Thread类实现多线程定义一个Thread的子类并重写其run方法.*/

public class MyThread extends Thread {

@Override

public void run() {

while (true) {

System.out.println("invoke MyThread run method");

}

}

public static void main(String[] args) { // main方法测试线程的创建与启动

MyThread myThread = new MyThread(); // 实例化MyThread的对象

myThread.start(); // 调用myThread对象的start方法启动一个线程}

}

3、利用实现Runable接口创建线程的示例

package com.px1987.j2se.thread.base;

/**通过Runable接口实现多线程定义MyRunable类实现Runnable接口,并实现接口中的run方法。*/

public class MyRunable implements Runnable {

public void run() {

while (true)

System.out.println("invoke MyRunable run method");

}

public static void main(String[] args) { // main方法测试线程的创建与启动// 建立MyRunable类的对象,以此对象为参数建立Thread类的对象

Thread thread = new Thread(new MyRunable());

thread.start(); // 调用thread对象的start方法启动一个线程

}

}

6.3 线程的状态控制

1、新建状态

用new关键字和Thread类或其子类建立一个线程对象后,该线程对象就处于新生状态。处于新生状态的线程有自己的内存空间,通过调用start方法进入就绪状态(runnable)。

2、就绪状态

处于就绪状态的线程已经具备了运行条件,但还没有分配到CPU,处于线程就绪队列,等待系统为其分配CPU。等待状态并不是执行状态,当系统选定一个等待执行的Thread对象后,它就会从等待执行状态进入执行状态,系统挑选的动作称之为“cpu调度”。一旦获得CPU,线程就进入运行状态并自动调用自己的run方法。

3、死亡状态

死亡状态是线程生命周期中的最后一个阶段。线

程死亡的原因有两个:

一个是正常运行的线程完成了它的全部工作;

另一个是线程被强制性地终止,如通过执行stop

或destroy方法来终止一个线程。

Method stop() & destroy() in the class Thread is

deprecated。

当一个线程进入死亡状态以后,就不能再回到其它状态了。让一个Thread对象重新执行一次的唯一方法,就是重新产生一个Thread对象。

4、体现线程状态转变的代码示例

package com.px1987.j2se.thread.base;

public class MyRunable1 implements Runnable {

public void run() {

while (true)

System.out.println("invoke MyRunable run method");

}

public static void main(String[] args) {

Thread thread = new Thread(new MyRunable()); // 新生状态

thread.start(); // 就绪状态,获得CPU后就能运行

try {

Thread.sleep(5000);

} catch (InterruptedException e) {

e.printStackTrace();

}

thread.stop(); // 死亡状态

}

}

通过查API可以看到stop方法和destory方法已经过时了,所以不能再用,那要怎样做才能强制的销毁一个线程呢?

1、在run方法中执行return 线程同样结束

2、可以在while循环的条件中设定一个标志位,当它等于false的时候,while循环就不在运行,这样线程也就结束了。代码为实现的代码示例:

package com.px1987.j2se.thread.StateControl;

public class MyRunable2 implements Runnable {

private boolean isStop; //线程是否停止的标志位

public void run() {

while (!isStop)

System.out.println("invoke MyRunable run method");

}

public void stop(){ //终止线程

isStop=true;

}

public static void main(String[] args) {

MyRunable myRunable=new MyRunable();

Thread thread = new Thread(myRunable);

thread.start();

try {

Thread.sleep(5000);

}

catch (InterruptedException e) {

e.printStackTrace();

}

myRunable.stop(); //正确的停止线程的方法

}

}

5、阻塞状态

处于运行状态的线程在某些情况下,如执行了sleep

(睡眠)方法,或等待I/O设备等资源,将让出CPU并

暂时停止自己的运行,进入阻塞状态。

在阻塞状态的线程不能进入就绪队列。只有当引起

阻塞的原因消除时,如睡眠时间已到,或等待的I/O设

备空闲下来,线程便转入就绪状态,重新到就绪队列中

排队等待,被系统选中后从原来停止的位置开始继续运行。有三种方法可以暂停Threads执行:

(1)sleep方法

可以调用Thread的静态方法:public static void sleep(long millis) throws InterruptedException 使得当前线程休眠(暂时停止执行millis毫秒)。由于是静态方法,sleep 可以由类名直接调用:Thread.sleep(…)。下面为代码示例:

package com.px1987.j2se.thread.p5;

import java.util.Date;

import java.text.SimpleDateFormat;

class SleepTest implements Runnable {

private static SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");

public void run() {

System.out.println("child thread begin");

int i = 0;

while (i++ < 5) {

System.out.println(format.format(new Date()));

try {

Thread.sleep(5000);

}

catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println("child thread dead at: " + format.format(new Date()));

}

public static void main(String[] args) {

Runnable r = new SleepTest();

Thread thread = new Thread(r);

thread.start();

try {

Thread.sleep(20000);

}

catch (InterruptedException e) {

e.printStackTrace();

}

thread.interrupt();

System.out.println("main method dead!");

}

}

该程序的运行结果如下:

child thread begin

2009-02-06 04:50:29

2009-02-06 04:50:34

2009-02-06 04:50:39

2009-02-06 04:50:44

main method dead!

https://www.doczj.com/doc/f92514824.html,ng.InterruptedException: sleep interrupted

at https://www.doczj.com/doc/f92514824.html,ng.Thread.sleep(Native Method)

at com.px1987.j2se.thread.p5.Thread4.run(Thread4.java:17)

at https://www.doczj.com/doc/f92514824.html,ng.Thread.run(Unknown Source)

2009-02-06 04:50:49

child thread dead at: 2009-02-06 04:50:54

(2)yield方法

让出CPU的使用权,从运行态直接进入就绪态。下面为代码示例:

package com.px1987.j2se.thread.StateControl;

class Thread5 implements Runnable {

private String name;

Thread5(String s) {

https://www.doczj.com/doc/f92514824.html, = s;

}

public void run() {

for (int i = 1; i <= 50; i++) {

System.out.println(name + ": " + i);

if (i % 10 == 0) {

Thread.yield();

}

}

}

package com.px1987.j2se.thread.StateControl;

public class YieldTest {

public static void main(String[] args) {

Runnable r1 = new Thread5("S1");

Runnable r2 = new Thread5("S2");

Thread t1 = new Thread(r1);

Thread t2 = new Thread(r2);

t1.start();

t2.start();

try {

Thread.sleep(2);

}

catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println("main method over!");

}

}

该程序的部分运行结果如下:

S1: 20

S2: 7

S2: 8

S2: 9

S2: 10

S1: 41

S1: 42

S1: 43

S1: 44

S1: 45

S1: 46

S1: 47

S1: 48

S1: 49

S1: 50

S2: 11

S2: 12

(3)join方法

当某个(A)线程等待另一个线程(B)执行结束后,才继续执行时,使用join方法。A的run 方法调用b.join()。下面为代码示例。

package com.px1987.j2se.thread.join;

class FatherThread implements Runnable {

public void run() {

System.out.println("爸爸想抽烟,发现烟抽完了");

System.out.println("爸爸让儿子去买包红塔山");

Thread son = new Thread(new SonThread());

son.start();

System.out.println("爸爸等儿子买烟回来");

try { //join含义:等待son线程执行完毕,father线程才继续执行son.join();

}

catch (InterruptedException e) {

System.out.println("爸爸出门去找儿子跑哪去了");

System.exit(1);

}

System.out.println("爸爸高兴的接过烟开始抽,并把零钱给了儿子");

}

}

package com.px1987.j2se.thread.join;

class SonThread implements Runnable {

public void run() {

String tabs="\t\t\t\t\t\t";

System.out.println(tabs+"儿子出门去买烟");

System.out.println(tabs+"儿子买烟需要10分钟");

try {

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

Thread.sleep(1000);

System.out.println(tabs+"儿子出去第" + ++i + "分钟");

}

}

catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println(tabs+"儿子买烟回来了");

}

}

package com.px1987.j2se.thread.join;

public class JoinTest {

public static void main(String[] args) {

System.out.println("爸爸和儿子的故事");

Thread father = new Thread(new FatherThread());

father.start();

// try {

// Thread.sleep(5000);

// } catch (InterruptedException e) {

// e.printStackTrace();

// }

// father.interrupt();

}

}

该程序的运行结果如下:

爸爸和儿子的故事

爸爸想抽烟,发现烟抽完了

爸爸让儿子去买包红塔山

爸爸等儿子买烟回来

儿子出门去买烟

儿子买烟需要10分钟

儿子出去第1分钟

儿子出去第2分钟

儿子出去第3分钟

儿子出去第4分钟

儿子出去第5分钟

儿子出去第6分钟

儿子出去第7分钟

儿子出去第8分钟

儿子出去第9分钟

儿子出去第10分钟

儿子买烟回来了

爸爸高兴的接过烟开始抽,并把零钱给了儿子

当时间来到儿子出去买烟的时候,Father线程调用interrupt方法就会打断son线程的正常执行,从而father线程也就不必等待son线程执行完毕再行动了,运行结果如下:

爸爸和儿子的故事

爸爸想抽烟,发现烟抽完了

爸爸让儿子去买包红塔山

爸爸等儿子买烟回来

儿子出门去买烟

儿子买烟需要10分钟

儿子出去第1分钟

儿子出去第2分钟

儿子出去第3分钟

儿子出去第4分钟

爸爸出门去找儿子跑哪去了

6.4线程的调度和优先级

1、线程的基本信息

方法功能

isAlive()判断线程是否还“活”着,即线程是否还未终止。

getPriority()获得线程的优先级数值

setPriority()设置线程的优先级数值

setName()给线程一个名字

getName()取得线程的名字

currentThread()取得当前正在运行的线程对象,也就是取得自己本身

2、操作线程的基本信息代码示例

package com.px1987.j2se.thread.priority;

public class ThreadInfoTest {

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

Runnable r = new MyThread();

Thread t = new Thread(r, "Name test");

t.start();

System.out.println("name is: " + t.getName());

Thread.currentThread().sleep(5000);

System.out.println(t.isAlive());

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

}

}

class MyThread implements Runnable {

public void run() {

for (int i = 0; i < 100; i++)

System.out.println(i);

}

}

该程序的运行结果如下:

name is: Name test

1

2

3

. . .

97

98

99

false

over!

3、线程的优先级

(1)优先级(共10级):

它们决定线程执行的先后次序(优先级高者先执行)并可以通过Thread类中的setPriority()和getPriority()方法来改变和获取优先级。典型的优先级码

?Thread.MIN_PRIORITY(1级)

?Thread.MAX_PRIORITY(10级)

?Thread.NORM_PRIORITY(5级)

(2)调度规则

Java是不支持线程时间片轮换的调度模型,而采用的是线程优先级高低的抢占调度模型。具有高优先级的线程可以抢占低优先级线程运行的机会。高优先级的线程将始终获得线程执行时间。但是这也不是绝对的,java线程调度器有可能会调用长期处于等待的线程进行执行,所以不要依靠线程的高优先级抢占模型去完成某些功能。

Java线程调度器支持不同优先级线程的抢先方式,但其本身不支持相同优先级线程的时间片轮换。但是如果java运行时系统所在的操作系统(如windows2000)支持时间片的轮换,则线程调度器就支持相同优先级线程的时间片轮换。

(3)代码示例

package com.px1987.j2se.thread.priority;

public class ThreadPriorityTest {

public static void main(String[] args) {

Thread t1 = new Thread(new MyThread2(), "t1");

Thread t2 = new Thread(new MyThread2(), "t2");

t1.setPriority(1);

t2.setPriority(10);

t1.start();

t2.start();

}

}

class MyThread2 extends Thread {

public void run() {

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

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

yield();

}

}

}

该程序的运行结果如下:

t1: 0

t2: 0

t2: 1

t2: 2

t2: 3

t2: 4

t2: 5

t2: 6

t2: 7

t2: 8

t2: 9

t1: 1

t1: 2

t1: 3

t1: 4

t1: 5

t1: 6

t1: 7

t1: 8

t1: 9

6.5线程同步互斥

1、线程同步互斥的一个示例

多个线程同时访问或操作同一资源时,很容易出现数据前后不一致的问题。请看下面的例子:

男孩拿着折子去北京银行海淀分行取钱

女孩拿着男孩的银行卡去西单百货疯狂购物

男孩走到柜台钱询问帐户余额

银行的业务员小姐亲切地告诉他:"您还有10000元!"。

女孩看上了一件时髦的衣裳,准备买下

男孩在思考要取多少钱呢?

女孩到收银台准备刷卡消费

收银台刷卡机读取银行卡余额为10000元

女孩买衣服刷卡消费5000元

消费清单打印出来,消费:5000元余额:5000元

女孩离开商场

男孩思考了1毫秒

男孩决定取5000元

银行的业务员小姐为男孩办理相关业务手续

交易完成

银行的业务员小姐告诉男孩:"您的余额为5000元"。

男孩离开银行

男孩帐户中一共有10000元,男孩拿着存折从银行取走5000元,女孩拿着男孩的银行卡购物刷卡消费5000元,最后男孩的帐户里却还剩5000元。显然这是不正确的,但是为什么会发生这样的情况呢?我们可以这样分析:男孩可以看作是一条线程,女孩也可以看作是一条线程,在同一时刻,两个线程都操作了同一个资源,那就是男孩的帐户。男孩从查看帐户余额到取走现金应该被看作是个原子性操作,是不可再分的,然而当男孩查看完余额正思考取多少钱的时候,女孩购物消费了5000元,也就是说女孩这条线程打断了男孩这条线程所要执行的任务。所以男孩刚查看完的余额10000元就不正确了,最终导致帐户中少减了5000元。

为了避免这样的事情发生,我们要保证线程同步互斥,所谓同步互斥就是:并发执行的多个线程在某一时间内只允许一个线程在执行以访问共享数据

2、Java中线程互斥的实现机制

由多线程带来的性能改善是以可靠性为代价的,所以编程出线程安全的类代码是十分必要的。当多个线程可以访问共享资源(调用单个对象的属性和方法,对数据进行读、写、修改、删除等操作)时,应保证同时只有一个线程访问共享数据,Java对此提出了有效的解决方案—同步锁。任何线程要进入同步互斥方法(访问共享资源的方法或代码段)时,就必须得到这个共享资源对象的锁,线程进入同步互斥方法后其它线程则不能再进入同步互斥方法,直到拥有共享资源对象锁的线程执行完同步互斥方法释放了锁,下一个线程才能进入同步互斥方法被执行。

Java的这一线程互斥的实现机制可以用一个最通俗的比方来说明:比如公共卫生间就是一个共享资源,每个人都可以使用,但又不能同时使用,所以卫生间里有一把锁。一个人进去了,会把门锁上,其他人就不能进去。当Ta出来的时候,要打开锁,下一个人才能继续使用。

3、利用Synchronized关键字用于修饰同步互斥方法

(1)同步互斥方法

public synchronized void method(){

//允许访问控制的代码

}

(2)同步互斥代码块

synchronized(syncObject){

//允许访问控制的代码

}

(3)锁定整个类

public synchronized class SyncObject{

}

由于synchronized 块可以针对任意的代码块,且可任意指定上锁的对象,因此灵活性较高。但要注意:

●synchronized可以用来限定一个方法或一小段语句或整个类(该类中的所有方法都

是synchronized方法)

●将访问共享数据的代码设计为synchronized方法

●由于可以通过 private 关键字来保证数据对象只能被方法访问,所以只需针对方

法提出一套同步锁定机制。通过synchronized 方法来控制对类中的成员变量(共

享数据)的访问。

●编写线程安全的代码会使系统的总体效率会降低,要适量使用

●只有某一个线程的synchronized方法执行完后其它线程的synchronized方法才能被

执行。

●当前时间,只有一个线程访问被锁定的代码段,但不能保证其他线程去访问其他没

有被锁定的代码段。因此所有对共享资源进行操作的代码段都应该加锁。

●对数据库操作时,修改数据的线程要加锁,而读数据的线程可以不加锁

有了这种解决方案,我们用线程安全的代码来重新实现一下男孩和女孩取钱的故事。以下是核心代码:

package com.px1987.j2se.thread.synchronous.v2;

/** 帐户类 */

public class Account {

/** 余额 */

private int balance;

public Account(int balance) {

this.balance = balance;

}

}

package com.px1987.j2se.thread.synchronous.v2;

/** 男孩类,实现Runnable接口*/

public class Boy implements Runnable {

/** 银行帐户*/

Account account;

public Boy(Account account) {

this.account = account;

}

/** 男孩拿着折子去北京银行海淀分行取钱*/

public void run() {

System.out.println("男孩拿着折子去北京银行海淀分行取钱");

synchronized (account) {

System.out.println("男孩走到柜台钱询问帐户余额");

int balance = account.getBalance();

System.out.println("银行的业务员小姐亲切地告诉他:\"您还有" +

balance + "元!\"。");

try {

System.out.println("男孩在思考要取多少钱呢?");

Thread.sleep(1);

System.out.println("男孩思考了1毫秒");

}

catch (InterruptedException e) {

e.printStackTrace();

}

int money = 5000;

System.out.println("男孩决定取" + money + "元");

System.out.println("银行的业务员小姐为男孩办理相关业务手续");

account.setBalance(balance - money);

System.out.println("交易完成");

System.out.println("银行的业务员小姐告诉男孩:\"您的余额为" +

account.getBalance()+ "元\"。");

}

System.out.println("男孩离开银行");

}

}

package com.px1987.j2se.thread.synchronous.v2;

/** 女孩类,实现runnable接口*/

public class Girl implements Runnable {

/** 女孩持有男孩的银行卡*/

Account account;

public Girl(Account account) {

this.account = account;

}

/*** "女孩拿着小军的银行卡去西单百货疯狂购物*/

public void run() {

String tabs = "\t\t\t\t\t\t";

System.out.println(tabs + "女孩拿着小军的银行卡去西单百货疯狂购物");

System.out.println(tabs + "女孩看上了一件时髦的衣裳,准备买下");

synchronized (account) {

System.out.println(tabs + "女孩到收银台准备刷卡消费");

int balance = account.getBalance();

System.out.println(tabs + "收银台刷卡机读取银行卡余额为" + balance + "元");

int payout = 5000;

System.out.println(tabs + "女孩买衣服刷卡消费" + payout + "元");

account.setBalance(balance - payout);

System.out.println(tabs + "消费清单打印出来,消费:" + payout + "元" + " 余额:"

+ account.getBalance() + "元");

}

System.out.println(tabs + "女孩离开商场");

}

}

package com.px1987.j2se.thread.synchronous.v2;

public class Bank {

public static void main(String[] args) {

Account account=new Account(10000);

Thread boyThread=new Thread(new Boy(account));

Thread girlThread=new Thread(new Girl(account));

boyThread.start();

girlThread.start();

}

}

修改后的代码运行结果如下图:

男孩拿着折子去北京银行海淀分行取钱

女孩拿着小军的银行卡去西单百货疯狂购物

女孩看上了一件时髦的衣裳,准备买下

女孩到收银台准备刷卡消费

收银台刷卡机读取银行卡余额为10000元

女孩买衣服刷卡消费5000元

消费清单打印出来,消费:5000元余额:

5000元

女孩离开商场

男孩走到柜台钱询问帐户余额

银行的业务员小姐亲切地告诉他:"您还有5000元!"。

男孩在思考要取多少钱呢?

男孩思考了1毫秒

男孩决定取5000元

银行的业务员小姐为男孩办理相关业务手续

交易完成

银行的业务员小姐告诉男孩:"您的余额为0元"。

男孩离开银行

从结果中可以看出来,男孩从查看余额到取钱,女孩没有操作帐户,所以最后的余额是正确的。

4、线程死锁

使用互斥锁容易产生死锁问题。比如:一个线程需要锁定两个对象才能完成,线程1拥有对象A的锁,线程1如果再拥有对象B的锁就能完成操作,线程2拥有对象B的锁,线程2如果再拥有对象A的锁就能完成操作。

很不幸的是线程1执行不下去了,因为线程1等待的资源对象B被线程2锁住了,线程2也执行不下去了,因为线程2等待的资源对象A被线程1锁住了,这样就造成了死锁。

阅读一段文字:由多线程带来的性能改善是以可靠性为代价的,主要是因为有可能产生线程死锁。死锁是这样一种情形:多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放。由于线程被无限期地阻塞,因此程序不能正常运行。简单的说就是:线程死锁时,第一个线程等待第二个线程释放资源,而同时第二个线程又在等待第一个线程释放资源。这里举一个通俗的例子:如在人行道上两个人迎面相遇,为了给对方让道,两人同时向一侧迈出一步,双方无法通过,又同时向另一侧迈出一步,这样还是无法通过。假设这种情况一直持续下去,这样就会发生死锁现象。

导致死锁的根源在于不适当地运用“synchronized”关键词来管理线程对特定对象的访问。“synchronized”关键词的作用是,确保在某个时刻只有一个线程被允许执行特定的代码块,因此,被允许执行的线程首先必须拥有对变量或对象的排他性访问权。当线程访问对象时,线程会给对象加锁,而这个锁导致其它也想访问同一对象的线程被阻塞,直至第一个线程释放它加在对象上的锁。

(1)死锁问题的一个代码示例

package com.px1987.j2se.thread.DeadLock;

class Thread1 implements Runnable {

private Object a;

private Object b;

public Thread1(Object a, Object b) {

super();

this.a = a;

this.b = b;

}

public void run() {

synchronized (a) {

System.out.println("Thread1获得对象a的锁");

try {

Thread.sleep(1);

}

catch (InterruptedException e) {

e.printStackTrace();

}

synchronized (b) {

System.out.println("Thread1获得对象b的锁");

try {

Thread.sleep(1);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

}

}

package com.px1987.j2se.thread.DeadLock;

class Thread2 implements Runnable {

private Object a;

private Object b;

public Thread2(Object a, Object b) {

super();

this.a = a;

this.b = b;

}

public void run() {

synchronized (b) {

System.out.println("Thread2获得对象b的锁");

try {

Thread.sleep(1);

}

catch (InterruptedException e) {

e.printStackTrace();

}

synchronized (a) {

System.out.println("Thread2获得对象a的锁");

try {

Thread.sleep(1);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

}

}

package com.px1987.j2se.thread.DeadLock;

public class TestDeadLock {

public static void main(String[] args) {

Object a=new Object();

Object b=new Object();

Thread thread1=new Thread(new Thread1(a,b));

Thread thread2=new Thread(new Thread2(a,b));

thread1.start();

thread2.start();

}

}

下面是运行结果:

(2)死锁问题的另一个代码示例

package com.px1987.j2se.thread.DeadLock;

public class ThreadDeadLock {

public static void main(String[] args) {

ThreadOne threadOne=new ThreadOne();

ThreadTwo threadTwo=new ThreadTwo();

String s1="s";

String s2="sss";

threadOne.op1=s1;

threadTwo.op1=s1;

threadOne.op2=s2;

threadTwo.op2=s2;

threadOne.start();

threadTwo.start();

}

}

class ThreadOne extends Thread{

String op1;

String op2;

public void run(){// 同步中又有同步,就可能死锁

synchronized(op1){

System.out.println(Thread.currentThread().getName()+"锁定op1");

try {

Thread.sleep(1000);

} catch (InterruptedException e) {

e.printStackTrace();

}

synchronized(op2){

System.out.println(Thread.currentThread().getName()+"锁定op2");

}

}

}

}

class ThreadTwo extends Thread{

String op1;

String op2;

public void run(){

synchronized(op2){

System.out.println(Thread.currentThread().getName()+"锁定op2");

try {

Thread.sleep(1000);

} catch (InterruptedException e) {

e.printStackTrace();

}

synchronized(op1){

System.out.println(Thread.currentThread().getName()+"锁定op1");

}

}

}

}

6.6生产者消费者问题

1、生产者消费者问题的示例

生产者消费者问题也是一个典型的线程问题。我们举一个这方面的实例来说明:在一个果园里,有农夫和小孩,农夫会不停的采摘水果放入果园中心的一个水果筐直到水果筐满,而小孩会不停的从水果筐里拿水果来吃,直到水果拿完。分析这个模型我们可以看出:农夫可以看成是一个生产者的线程,小孩可以看成是一个消费者的线程,而大水果筐是共享资源。

2、用Java程序表述的代码示例

package com.px1987.j2se.thread.ProducerConsumer;

import java.util.Random;

/*** 水果类*/

public class Fruit {

/*** 水果编号*/

private int id;

/*** 水果编号计数器*/

private static int number = 0;

/*** 水果品种 */

private String variety;

/*** 水果品种数组 */

private String[] varietys = "苹果,桃子,梨子,香蕉,西瓜,荔枝,葡萄".split(",");

public Fruit() {

super();

this.variety = varietys[new Random().nextInt(7)];

this.id = ++number;

}

}

水果筐应该设计成类似于栈的数据结构,其中包含一个数组来存放筐里的水果,而数组的下标就是水果筐的容量。设定一个索引index表示指向下一个将要放入水果的位置。类中的push方法模拟农夫向水果筐中放入水果,pop方法模拟小孩从水果筐中拿水果。这两个方法都要操作共享资源,所以push和pop方法都是同步互斥方法。

3、如何避免出现死锁

那同步的问题解决后是否会出现死锁呢?大家试想一下,如果生产的速度大于消费的速度就会导致功大于求,水果筐很容易就满了,然而生产者又一直抱着水果筐不放,没有机会给消费者使用,消费者不消费生产者就无法生产,所以就造成了死锁。

怎样解决呢?在两个同步互斥方法中用到了wait和notify方法,这两个方法是为了防止死锁的。

●wait是Object类的方法,它的作用是拥有互斥锁的线程放弃锁的使用权,进入

wait池进行等待,那么互斥锁就有可能被其他线程获得以执行其他任务。

●notify也是Object类的方法,它的作用是从wait池中唤醒一条正在等待的线

程进入就绪状态,被唤醒的这条线程就很可能重新获得cup和互斥锁来完成它的

任务。

●notifyAll和Notify很相似,它是从wait池中唤醒所有正在等待的线程进入

就绪状态。

需要注意的是以上三个方法都只能在synchronized方法中应用,否者会出现下面的异常信息:IllegalMonitorStateException:current thread not owner。

4、实现的代码示例

package com.px1987.j2se.thread.ProducerConsumer;

import java.text.DecimalFormat;

import java.util.Arrays;

/*** 水果框类,类似一个栈的模型 */

public class FruitBasket {

/*** 容量为10的水果数组,也就是说水果框最多能放下10个水果 */

private Fruit[] fruits = new Fruit[10];

/*** 下一个将要放入水果的位置*/

private int index = 0;

/*** 水果框中是否为空 @return true为空,false为不空 */

public boolean isEmpty() {

return index == 0 ? true : false;

/*** 水果框是否装满* @return true为满,false为未满*/

public boolean isFull() {

return index == fruits.length ? true : false;

}

/*** 进栈方法,模拟农夫把水果放入筐中,@param name 农夫的名字,@param fruit 水果对

象 */

public synchronized void push(String name, Fruit fruit) {

//用while循环,不用if,避免IndexOutOfBoundsException异常的产生

while (isFull()) {

//如果水果筐满了,需要等待

try {

this.wait();

}

catch (InterruptedException e) {

e.printStackTrace();

}

}

//将水果放入index指示的位置,index再上移一格

fruits[index++] = fruit;

System.out.println(name + " 向水果框中放入编号为" + fruit.getId() + "的"+

fruit.getVariety());

display();

this.notify(); //通知其他等待的农夫或孩子可以开始工作啦

}

/*** 出栈方法,模拟小孩从水果筐中取出水果,@param name 小孩的名字,@return 取出的水

果*/

public synchronized Fruit pop(String name) {

//用while循环,不用if,避免IndexOutOfBoundsException异常的产生

while (isEmpty()) {

try { //如果水果筐空,需要等待

this.wait();

}

catch (InterruptedException e) {

e.printStackTrace();

}

}

Fruit fruit = null;

fruit = fruits[--index]; //index下移一位,取出指示位置上的水果

System.out.println(name + " 从水果框中拿出编号为" + fruit.getId() + "的"+

fruit.getVariety());

display();

this.notify();

return fruit;

java线程练习题及答案

线程与线程类 1 线程的概念 线程的概念来源于计算机的操作系统的进程的概念。进程是一个程序关于某个数据集的一次运行。也就是说,进程是运行中的程序,是程序的一次运行活动。 线程和进程的相似之处在于,线程和运行的程序都是单个顺序控制流。有些教材将线程称为轻量级进程(light weight process)。线程被看作是轻量级进程是因为它运行在一个程序的上下文内,并利用分配给程序的资源和环境。 作为单个顺序控制流,线程必须在运行的程序中得到自己运行的资源,如必须有自己的执行栈和程序计数器。线程内运行的代码只能在该上下文内。因此还有些教程将执行上下文(execution context)作为线程的同义词。 所有的程序员都熟悉顺序程序的编写,如我们编写的名称排序和求素数的程序就是顺序程序。顺序程序都有开始、执行序列和结束,在程序执行的任何时刻,只有一个执行点。线程(thread )则是进程中的一个单个的顺序控制流。单线程的概念很简单,如图1所示。 多线程(multi-thread )是指在单个的程序内可以同时运行多个不同的线程完成不同的任务,图2说明了一个程序中同时有两个线程运行。 图1 单线程程序示意图 图2 多线程程序示意图 有些程序中需要多个控制流并行执行。例如, for(int i = 0; i < 100; i++) System.out.println("Runner A = " + i); for(int j = 0; j < 100; j++ ) System.out.println("Runner B = "+j); 上面的代码段中,在只支持单线程的语言中,前一个循环不执行完不可能执行第二个循环。要使两个循环同时执行,需要编写多线程的程序。 很多应用程序是用多线程实现的,如Hot Java Web 浏览器就是多线程应用的例子。在Hot Java 浏览器中,你可以一边滚动屏幕,一边下载Applet 或图像,可以同时播放动画和声音等。 2 Thread 类和Runnable 接口 多线程是一个程序中可以有多段代码同时运行,那么这些代码写在哪里,如何创建线程对象呢? 首先,我们来看Java 语言实现多线程编程的类和接口。在https://www.doczj.com/doc/f92514824.html,ng 包中定义了Runnable 接口和Thread 类。

Java第七单元练习题-Java多线程机制

7Java多线程机制 7.1单项选择题 1. 线程调用了sleep()方法后,该线程将进入()状态。 A. 可运行状态 B. 运行状态 C. 阻塞状态 D. 终止状态 2. 关于java线程,下面说法错误的是() A. 线程是以CPU为主体的行为 B. java利用线程使整个系统成为异步 C. 创建线程的方法有两种:实现Runnable接口和继承Thread类 D. 新线程一旦被创建,它将自动开始运行 3. 在java中的线程模型包含() A. 一个虚拟处理器 B. CPU执行的代码 C. 代码操作的数据 D. 以上都是 4.在java语言中,临界区可以是一个语句块,或者是一个方法,并用()关键字标识。 A. synchronized B. include C. import D. Thread 5. 线程控制方法中,yield()的作用是() A. 返回当前线程的引用 B. 使比其低的优先级线程执行 C. 强行终止线程 D. 只让给同优先级线程运行 6. 线程同步中,对象的锁在()情况下持有线程返回 A. 当synchronized()语句块执行完后 B. 当在synchronized()语句块执行中出现例外(exception)时 C. 当持有锁的线程调用该对象的wait()方法时 D. 以上都是 7. 在以下()情况下,线程就进入可运行状态 A. 线程调用了sleep()方法时 B. 线程调用了join()方法时

C. 线程调用了yield()方法时 D. 以上都是 8. java用()机制实现了进程之间的异步执行 A. 监视器 B. 虚拟机 C. 多个CPU D. 异步调用 类的方法中,toString()方法的作用是() A. 只返回线程的名称 B. 返回当前线程所属的线程组的名称 C. 返回当前线程对象 D. 返回线程的名称 语言具有许多优点和特点,下列选项中,哪个反映了Java程序并行机制的特点() A. 安全性 B. 多线程 C. 跨平台 D. 可移值 11.以下哪个关键字可以用来对对象加互斥锁?() A. transient B. synchronized C. serialize D. static 12.下面关于进程、线程的说法不正确的是( )。 A.进程是程序的一次动态执行过程。一个进程在其执行过程中,可以产生多个线程——多线程,形成多条执行线索。 B.线程是比进程更小的执行单位,是在一个进程中独立的控制流,即程序内部的控制流。线程本身不能自动运行,栖身于某个进程之中,由进程启动执行。 C.Java多线程的运行与平台无关。 D.对于单处理器系统,多个线程分时间片获取CPU或其他系统资源来运行。对于多处理器系统,线程可以分配到多个处理器中,从而真正的并发执行多任务。 7.2填空题 1.________是java程序的并发机制,它能同步共享数据、处理不同的事件。 2.线程是程序中的一个执行流,一个执行流是由CPU运行程序的代码、__________所形 成的,因此,线程被认为是以CPU为主体的行为。 3.线程的终止一般可以通过两种方法实现:自然撤销或者是__________. 4.线程模型在java中是由__________类进行定义和描述的。 5.线程的创建有两种方法:实现_________接口和继承Thread类。 6.多线程程序设计的含义是可以将程序任务分成几个________的子任务。 7.按照线程的模型,一个具体的线程也是由虚拟的CPU、代码与数据组成,其中代码与数 据构成了___________,线程的行为由它决定。 8.ava中,新建的线程调用start()方法、如(),将使线程的状态从New(新建状态)转换为 _________。 9.多线程是java程序的________机制,它能同步共享数据,处理不同事件。 10.进程是由代码、数据、内核状态和一组寄存器组成,而线程是表示程序运行状态的

java多线程实现调度

重庆交通大学综合性设计性实验报告 实验项目名称:进程调度(先来先服务) 实验项目性质: JAVA多线程 实验所属课程: JAVA程序设计 实验室(中心):语音大楼 8 楼 801 班级:软件专业 2012级2班 姓名:尚亚* 学号: 631206050216 指导教师:杨 实验完成时间: 2014 年 11 月 25 日

一、实验目的 1、理解程序、线程和进程的概念; 2、理解多线程的概念; 3、掌握线程的各种状态; 4、熟练使用Thread类创建线程; 5、熟练使用线程各种方法; 6、掌握线程的调度及线程同步的实现原理。 二、实验内容及要求 进程调度是处理机管理的核心内容。本实验要求采用最高优先数优先的调度算法(即把处理机分配给优先数最高的进程)和先来先服务算法编写和调试一个简单的进程调度程序。通过本实验可以加深理解有关进程控制块、进程队列的概念。并体会了优先数和先来先服务调度算法的具体实施办法。 用JA V A语言编写和调试一个进程调度程序,以加深对进程的概念及进程调度算法的理解。做一个能够直观体现多个进程时,CPU 是怎样调度就绪队列中的进程(按照先来先服务的原则)。

三、实验设备 PC机,windows7,eclipse。 四、设计方案 ㈠设计主要思想 (1)要模拟进程的调度算法,必须先体现处进程及系统资源。 (2)要体现先来先服务的算法,就必须表现出当有一个进程进入CPU时其他进程不能进入,并在就绪队列中排队。本实验建立了四个圆移动的线程表示作业调度,用圆在表示就绪队列的方框中停留表示进程在就绪队列中排队。 (3)当有一个圆移动到表示CPU的范围内时,让其它线程在就绪队列中排队,当CPU内无进程时,先来的圆先移动,以表示CPU 对进程的调度。 ㈡设计的主要步骤 (1)建立四个不同颜色的圆移动的线程,表示对四个进程的调度。 (2)当有一个表示进程的圆到达表示CPU范围内时,通过让其它几个圆停留在表示就绪队列的方框范围内,表示进程在就绪队列中排成队列。 (3)当第一个先到达的进程释放CPU,在排成队列的几个圆中选择先到达的圆,使其移动表示对先来的进程进行调度,直到所有的圆移动完毕。 五、主要代码 import java.awt.Font; import java.awt.event.*;

Java第七单元练习题Java多线程机制

J a v a第七单元练习题 J a v a多线程机制 The latest revision on November 22, 2020

7Java多线程机制 7.1单项选择题 1. 线程调用了sleep()方法后,该线程将进入()状态。 A. 可运行状态 B. 运行状态 C. 阻塞状态 D. 终止状态 2. 关于java线程,下面说法错误的是() A. 线程是以CPU为主体的行为 B. java利用线程使整个系统成为异步 C. 创建线程的方法有两种:实现Runnable接口和继承Thread类 D. 新线程一旦被创建,它将自动开始运行 3. 在java中的线程模型包含() A. 一个虚拟处理器 B. CPU执行的代码 C. 代码操作的数据 D. 以上都是 4.在java语言中,临界区可以是一个语句块,或者是一个方法,并用()关键字标识。 A. synchronized B. include C. import D. Thread 5. 线程控制方法中,yield()的作用是() A. 返回当前线程的引用 B. 使比其低的优先级线程执行 C. 强行终止线程 D. 只让给同优先级线程运行 6. 线程同步中,对象的锁在()情况下持有线程返回 A. 当synchronized()语句块执行完后 B. 当在synchronized()语句块执行中出现例外(exception)时 C. 当持有锁的线程调用该对象的wait()方法时 D. 以上都是 7. 在以下()情况下,线程就进入可运行状态 A. 线程调用了sleep()方法时 B. 线程调用了join()方法时 C. 线程调用了yield()方法时 D. 以上都是 8. java用()机制实现了进程之间的异步执行

java多线程 练习

1.如果线程死亡,它便不能运行。(T) 2.在Java中,高优先级的可运行线程会抢占低优先级线程。(T ) 3.线程可以用yield方法使低优先级的线程运行。(F) 4...程序开发者必须创建一个线程去管理内存的分配。(F) 5.一个线程在调用它的start方法,之前,该线程将一直处于出生期。(T) 6.当调用一个正在进行线程的stop( )方法时,该线程便会进入休眠状态。(F) 7.一个线程可以调用yield方法使其他线程有机会运行。(T) 二、选择题 1.Java语言中提供了一个▁D▁线程,自动回收动态分配的内存。 A.异步 B.消费者 C.守护 D.垃圾收集 2.Java语言避免了大多数的▁C▁错误。 A.数组下标越界 B.算术溢出 C.内存泄露 D.非法的方法参数 3.有三种原因可以导致线程不能运行,它们是▁ACD▁▁。 A.等待 B.阻塞 C.休眠 D.挂起及由于I/O操作而阻塞 4.当▁A方法终止时,能使线程进入死亡状态。 A.run B.setPrority C.yield D.sleep 5.用▁B▁方法可以改变线程的优先级。 A.run B.setPrority C.yield D.sleep 6.线程通过▁C▁方法可以使具有相同优先级线程获得处理器。 A.run B.setPrority C.yield D.sleep 7.线程通过▁D▁方法可以休眠一段时间,然后恢复运行。 A.run B.setPrority C.yield

8.方法resume( )负责重新开始▁D▁线程的执行。 A.被stop( )方法停止 B.被sleep( )方法停止 C.被wait( )方法停止 D.被suspend( )方法停止 9.▁BCD▁方法可以用来暂时停止当前线程的运行。 A.stop( ) B.sleep( ) C.wait( ) D.suspend( ) 三、简述题 1.简述程序、进程和线程之间的关系?什么是多线程程序? 答:程序是一段静态的代码,它是应用软件执行的蓝本。进程是程序的一次动态执行过程,它对应了从代码加载、执行到执行完毕的一个完整过程。这个过程也是进程本身从产生、发展、到消亡的过程。线程是比进程更小的单位。一个进程在其执行过程中,可以产生多个线程,形成多个执行流。每个执行流即每个线程也有它自身的产生、存在和消亡的过程,也是一个动态的概念。多线程程序是指一个程序中包含多个执行流。 2.线程有哪几个基本状态?它们之间如何转化?简述线程的生命周期。 答:新建状态,可运行状态,运行状态,阻碍状态,终止状态。对线程调用各种控制方法,就使线程从一种状态转换到另一种状态。线程的生命周期从新建开始,在可运行、运行和其他阻碍中循环,在可运行、运行、对象锁阻塞、等待阻塞中循环,最终在运行后run()方法结束后终止。 3.什么是线程调度?Java的线程调度采用什么策略? 答:在单个CPU上以某种顺序运行多个线程,称为线程的调度。Java的线程调度策略是一种优先级的抢先式调度。Java基于线程的优先级选择高优先级的线程进行运行。该线程将持续运行,直到它终止运行,或其他高优先级线程称为可运行的。 4.如何在Java程序中实现多线程? 答:1:通过Thread类的构造方法 2:通过实现Runnable接口创建线程、 3:通过继承Thread类创建线程 5.试简述Thread类的子类或实现Runnable接口两种方法的异同? 答:采用继承Thread类方法使程序代码简单,并可以在run()方法中直接调用线程的其他方法。而实现Runnable接口更符合面向对象设计的思想,因为从OO设计的角度,thread 类是虚拟CPU的封装,所以Thread的子类应该是关于CPU行为的类。但在继承Thread类之类构造线程的方法中,Thread类的子类大都是与CPU不相关的类。而实现Runnable接口的方法,将不影响Java类的体系,所以更加符合面向对象的设计思想。同时,实现了Runnable 接口的类可以用extends继承其他的类。 四、程序设计题 1.编写一个类,在类中定义: A:一个整型属性

JAVA多线程简单案例.

第一页在 Java 程序中使用多线程要比在 C 或 C++ 中容易得多,这是因为Java 编程语言提供了语言级的支持。本文通过简单的编程示例来说明 Java 程序中的多线程是多么直观。读完本文以后,用户应该能够编写简单的多线程程序。 为什么会排队等待?下面的这个简单的 Java 程序完成四项不相关的任务。这样的程序有单个控制线程,控制在这四个任务之间线性地移动。此外,因为所需的资源 ? 打印机、磁盘、数据库和显示屏 -- 由于硬件和软件的限制都有内在的潜伏时间,所以每项任务都包含明显的等待时间。因此,程序在访问数据库之前必须等待打印机完成打印文件的任务,等等。如果您正在等待程序的完成,则这是对计算资源和您的时间的一种拙劣使用。改进此程序的一种方法是使它成为多线程的。四项不相关的任务class myclass { static public void main(String args[] { print_a_file(; manipulate_another_file(; access_database(; draw_picture_on_screen(; } } 在本例中,每项任务在开始之前必须等待前一项任务完成,即使所涉及的任务毫不相关也是这样。但是,在现实生活中,我们经常使用多线程模型。我们在处理某些任务的同时也可以让孩子、配偶和父母完成别的任务。例如,我在写信的同时可能打发我的儿子去邮局买邮票。用软件术语来说,这称为多个控制(或执行)线程。可以用两种不同的方法来获得多个控制线程:多个进程在大多数操作系统中都可以创建多个进程。当一个程序启动时,它可以为即将开始的每项任务创建一个进程,并允许它们同时运行。当一个程序因等待网络访问或用户输入而被阻塞时,另一个程序还可以运行,这样就增加了资源利用率。但是,按照这种方式创建每个进程要付出一定的代价:设置一个进程要占用相当一部分处理器时间和内存资源。而且,大多数操作系统不允许进程访问其他进程的内存空间。因此,进程间的通信很不方便,并且也不会将它自己提供给容易的编程模型。线程线程也称为轻型进程 (LWP。因为线程只能在单个进程的作用域内活动,所以创建线程比创建进程要廉价得多。这样,因为线程允许协作和数据交换,并且在计算资源方面非常廉价,所以线程比进程更可取。线程需要操作系统的支持,因此不是所有的机器都提供线程。Java 编程语言,作为相当新的一种语言,已将线程支持与语言本身合为一体,这样就对线程提供了强健的支持。使用 Java 编程语言实现线程Jav

Java第七单元练习题Java多线程机制(20210109223217)

7 Java 多线程机制 7.1 单项选择题 1. 线程调用了sleep ()方法后,该线程将进入( )状态。 A. 可运行状态 B. 运行状态 C. 阻塞状态 D. 终止状态 2. 关于java 线程,下面说法错误的是() A. 线程是以CPU为主体的行为 B. java 利用线程使整个系统成为异步 C. 创建线程的方法有两种:实现Runnable 接口和继承Thread 类 D. 新线程一旦被创建,它将自动开始运行 3. 在java 中的线程模型包含() A. 一个虚拟处理器 B. CPU执行的代码 C. 代码操作的数据 D. 以上都是 4. 在java 语言中,临界区可以是一个语句块,或者是一个方法,并用()关键字标识。 A. synchronized B. include C. import D. Thread 5. 线程控制方法中,yield()的作用是() A. 返回当前线程的引用 B. 使比其低的优先级线程执行 C. 强行终止线程 D. 只让给同优先级线程运行 6. 线程同步中,对象的锁在()情况下持有线程返回 A. 当synchronized()语句块执行完后 B. 当在synchronized()语句块执行中出现例外( exception )时 C. 当持有锁的线程调用该对象的wait()方法时 D. 以上都是 7. 在以下()情况下,线程就进入可运行状态 A. 线程调用了sleep()方法时 B. 线程调用了join()方法时 C. 线程调用了yield()方法时 D. 以上都是 8. java 用()机制实现了进程之间的异步执行 A. 监视器 B. 虚拟机

(参考答案版)福建农林大学_java_实验七_多线程

Java面向对象程序设计 实验七 多线程 学号: 姓名: 学院:计算机与信息学院 专业班级: 指导老师:林志伟 2 015.12.3

1 .单线程实例的运行结果是: mainbegins12345678910111213141516171819202122 2 324252627282930313233343536373839404142434445 647484950ABCDEFGHIJKLMNOPQRSTUVWXYZa 4 bcdefghijklmnopqrstuvwxyzmainends 多线程视力的运行结果是: mainbeginsmainendsA1B2C3D4E5F6G7H8I9JKLMNO PQRS 10 T11U 12 V13 W 14X15 Y16Z 17 a18b 19 c20 d 21e22 f 23 g24 h25i 26j 27k 28l 29m30n31o32p33q34r35 s36 t 37u38v39w40x41y42z4344454647484950 多线程与单线程的区别在于多线程可以同时运行多段代码,提高程序的执行 效率。 2 .程序运行结果如下: mainprint0 Thread1print5 Thread1print6 Thread1print7 Thread1print8 Thread1print9 Thread2print0 Thread2print1 Thread2print2 Thread2print3 Thread2print4 Thread2print5 Thread2print6 Thread2print7 Thread2print8 Thread2print9 mainprint1 mainprint2 mainprint3 mainprint4 mainprint5 mainprint6 mainprint7 mainprint8 mainprint9 Thread1print0 Thread1print1 Thread1print2 Thread1print3 Thread1print4 Threads 类实现了Runnable 接口,故程序运行到了t1.start()时会创建一个新 的线程并运行t1.run()内部的代码,运行到t2.start()时会再创建一个新的线程, 并运行t2.run()内部的代码。虽然这个程序是多线程的,但是由于cpu 运行速 度过快,导致这个程序的运行结果跟单线程运行的结果没有区别。当将run() 方法中的循环次数增加到了100 时,就可以看出多线程运行结果与单线程运 行结果的不同了。

黑马程序员Java教程:TCP协议服务端多线程技术

TCP协议服务端多线程技术 代码: UploadTask.java 1.import https://www.doczj.com/doc/f92514824.html,.Socket; 2.import java.io.InputStream; 3.import java.io.FileOutputStream; 4.import java.io.File; 5.import java.io.OutputStream; 6. 7.public class UploadTask implements Runnable 8.{ 9. private Socket s; 10. 11. public UploadTask(Socket s){ 12. this.s = s; 13. } 14. 15. public void run(){ 16. 17. int count = 0; 18. 19. String ip = s.getInetAddress().getHostAddress(); 20. System.out.println(ip + "......connected"); 21. 22. try{ 23. InputStream in = s.getInputStream(); 24. 25. File dir = new File("c:\\pic"); 26. if(!dir.exists()){ 27. dir.mkdirs();

28. } 29. File file = new File(dir,ip + ".bmp"); 30. 31. //如果文件已经存在于服务端。 32. while(file.exists()){ 33. file = new File(dir,ip + "(" + (++count) + ").bmp"); 34. } 35. 36. FileOutputStream fos = new FileOutputStream(file); 37. 38. byte[] buf = new byte[1024]; 39. 40. int len = 0; 41. 42. while((len = in.read(buf)) != -1){ 43. fos.write(buf,0,len); 44. } 45. 46. OutputStream out = s.getOutputStream(); 47. 48. out.write("上传成功".getBytes()); 49. 50. fos.close(); 51. s.close(); 52. }catch(Exception e){ 53. e.printStackTrace(); 54. } 55. } 56.}

7Java第七单元练习测试题-Java多线程机制

7J a v a多线程机制7.1单项选择题 1. 线程调用了sleep()方法后,该线程将进入()状态。 A. 可运行状态 B. 运行状态 C. 阻塞状态 D. 2. 关于 A. C. D. 3. 在 A. C. D. 4.在 5. A. B. C. D. 6. A. 当 B. C. 当持有锁的线程调用该对象的wait()方法时 D. 以上都是 7. 在以下()情况下,线程就进入可运行状态 A. 线程调用了sleep()方法时 B. 线程调用了join()方法时 C. 线程调用了yield()方法时 D. 以上都是 8. java用()机制实现了进程之间的异步执行 A. 监视器 B. 虚拟机 C. 多个CPU

D. 异步调用 9.Thread类的方法中,toString()方法的作用是() A. 只返回线程的名称 B. 返回当前线程所属的线程组的名称 C. 返回当前线程对象 D. 返回线程的名称 10.Java语言具有许多优点和特点,下列选项中,哪个反映了Java程序并行机制的特点() A. 安全性 B. 多线程 C. 跨平台 D. 可移值 11. 12. A B C.Java D 7.2 1. 2.因 3. 4. 5. 6. 7. 了 8.ava)转 换为_________。 9.多线程是java程序的________机制,它能同步共享数据,处理不同事件。 10.进程是由代码、数据、内核状态和一组寄存器组成,而线程是表示程序运行状态的______,如 程序计数器、栈指针以及堆栈组成。 11.Thread类提供了一系列基本线程控制方法,如果我们需要让与当前进程具有相同优先级的线程 也有运行的机会则可以调用________方法。 12.在多线程系统中,多个线程之间有________和互斥两种关系。 13. 在一个时间只能由一个线程访问的资源称为临界资源,访问临界资源的代码___________。

相关主题
文本预览
相关文档 最新文档