答:
有两种实现方法,分别是继承Thread类与实现Runnable接口。
用synchronized关键字修饰同步方法,反对使用stop(),是因为它不安全。
它会解除由线程获取的所有锁定,而且如果对象处于一种不连贯状态,那么其他线程能在那种状态下检查和修改它们。结果很难检查出真正的问题所在。
suspend()方法容易发生死锁。调用suspend()的时候,目标线程会停下来,但却仍然持有在这之前获得的锁定。此时,其他任何线程都不能访问锁定的资源,除非被"挂起"的线程恢复运行。
对任何线程来说,如果它们想恢复目标线程,同时又试图使用任何一个锁定的资源,就会造成死锁。所以不应该使用suspend(),而应在自己的Thread类中置入一个标志,
指出线程应该活动还是挂起。
若标志指出线程应该挂起,便用wait()命其进入等待状态。若标志指出线程应当恢复,则用一个notify()重新启动线程。
答:
sleep是线程类(Thread)的方法,导致此线程暂停执行指定时间,给执行机会给其他线程,
但是监控状态依然保持,到时后会自动恢复。调用sleep不会释放对象锁。
wait是Object类的方法,对此对象调用wait方法导致本线程放弃对象锁,
进入等待此对象的等待锁定池,只有针对此对象发出notify方法(或notifyAll)后本线程才进入对象锁定池准备获得对象锁进入运行状态。
答:
如果数据将在线程间共享。例如正在写的数据以后可能被另一个线程读到,
或者正在读的数据可能已经被另一个线程写过了,那么这些数据就是共享数据,必须进行同步存取。
当应用程序在对象上调用了一个需要花费很长时间来执行的方法,并且不希望让程序等待方法的返回时,
就应该使用异步编程,在很多情况下采用异步途径往往更有效率。
答:
启动一个线程是调用start()方法,使线程所代表的虚拟处理机处于可运行状态,
这意味着它可以由JVM调度并执行。这并不意味着线程就会立即运行。
run()方法就是正常的对象调用方法的执行,并不是使用分线程来执行的。
答:不能,一个对象的一个synchronized方法只能由一个线程访问。
答:
wait():使一个线程处于等待状态,并且释放所持有的对象的lock。
sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要捕捉InterruptedException异常。
notify():唤醒一个处于等待状态的线程,注意的是在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由JVM确定唤醒哪个线程,而且不是按优先级。
notityAll():唤醒所有处入等待状态的线程,注意并不是给所有唤醒线程一个对象的锁,而是让它们竞争。
答:
多线程有两种实现方法,分别是继承Thread类与实现Runnable接口
同步的实现方面有两种,分别是synchronized,wait与notify
答:
线程指在程序执行过程中,能够执行程序代码的一个执行单位,每个程序至少都有一个线程,也就是程序本身。
Java中的线程有四种状态分别是:创建、就绪、运行、阻塞、结束
答:
主要相同点:Lock能完成synchronized所实现的所有功能
主要不同点:Lock有比synchronized更精确的线程语义和更好的性能。
synchronized会自动释放锁,而Lock一定要求程序员手工释放,并且必须在finally从句中释放。
public class Demo01 {
public static void main(String[] args) {
//三个线程间的通讯
MyTask task = new MyTask();
new Thread(){
public void run() {
while(true){
try {
task.task1();
} catch (InterruptedException e1) {
e1.printStackTrace();
}
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
}.start();
new Thread(){
public void run() {
while(true){
try {
task.task2();
} catch (InterruptedException e1) {
e1.printStackTrace();
}
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
}.start();
new Thread(){
public void run() {
while(true){
try {
task.task3();
} catch (InterruptedException e1) {
e1.printStackTrace();
}
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
}.start();
}
}
class MyTask{
//标识 1:可以执行任务1,2:可以执行任务2, 3:可以执行任务3
int flag = 1;
public synchronized void task1() throws InterruptedException{
if(flag != 1){
this.wait();//当前线程等待
//this.wait(timeout);
}
System.out.println("1.银行信用卡自动还款任务...");
flag = 2;
//this.notify();//唤醒随机线程
this.notifyAll();//唤醒所有等待线程
}
public synchronized void task2() throws InterruptedException{
if(flag != 2){
this.wait();//线程等待
}
System.out.println("2.银行储蓄卡自动结算利息任务...");
flag = 3;
//this.notify();//唤醒其它线程
this.notifyAll();
}
public synchronized void task3() throws InterruptedException{
if(flag != 3){
this.wait();//线程等待
}
System.out.println("3.银行短信提醒任务...");
flag = 1;
//this.notify();//唤醒其它线程
this.notifyAll();
}
}
答案】
1.难度:容易
答案:错误
知识点:C 是单线程语言。
2.难度:容易
答案:正确
知识点:线程死亡就意味着它不能运行。
3.难度:适中
答案:正确
知识点:线程优先级的使用。
4.难度:适中
答案:错误
知识点:Java 提供了一个系统线程来管理内存的分配。
5.难度:容易
答案:正确
知识点:出生期的概念。
6.难度:适中
答案:错误
知识点:应该是 sleep 方法。
7.难度:适中
答案:错误
知识点:如果线程的 run 方法执行结束或抛出一个不能捕获的例外,线程便进入死亡状态。
8.难度:适中
答案:正确
知识点:yield 方法总是让高优先级的就绪线程先运行。
A 异步
B 消费者
C 守护
D 垃圾收集
A run
B setPrority
C yield
D sleep
A run
B setPrority
C yield
D sleep
A run
B setPrority
C yield
D sleep
A run
B setPrority
C yield
D sleep
A run
B notify
C yield
D sleep
A 被 stop( )方法停止
B 被 sleep( )方法停止
C 被 wait( )方法停止
D 被 suspend( )方法停止
A stop( )
B sleep( )
C wait( )
D suspend()
【答案】
1.难度:容易
答案:D
知识点:垃圾线程的使用。
2.难度:容易
答案:A
知识点:run 方法的使用。
3.难度:容易
答案:B
知识点:setPrority 方法的使用。
4.难度:容易
答案:C
知识点:yield 方法的使用。
5.难度:容易
答案:D
知识点:sleep 方法的使用。
6.难度:容易
答案:B
知识点:notify 方法的使用。
7.难度:适中
答案:D
知识点:一个线程被用 suspend( )方法,将该线程挂起。并通过调用 resume( )方法来重新开始线程的执行。
但是该方法容易导致死锁,应尽量避免使用。
8.难度:适中
答案:BCD
知识点:当调用 stop( )方法后,当前的线程不能重新开始运行。
答:
线程可以彼此独立的执行,它是一种实现并发机制的有效手段,可以同时使用多个线程来完成不同的任务,并且一般用户在使用多线程时并不考虑底层处理的细节。
程序是一段静态的代码,是软件执行的蓝本。进程是程序的一次动态执行过程,即是处于运行过程中的程序。
线程是比进程更小的程序执行单位,一个进程可以启动多个线程同时运行,不同线程之间可以共享相同的内存区域和数据。
多线程程序是运行时间后嗣可能出现在一个进程之内的、有一个以上线程同时运行的情况的程序。
答:
Runnable接口中仅有run()抽象方法。
Thread类主要域有:MAX_PRIORITY,MIN_PRIORITY,NORM_PRIORITY。
主要方法有start(),run(),sleep(),currentThread(),setPriority(),getPriority(),join()等。
1—继承Thread类
1) 定义类继承Thread类。
2) 覆盖Thread类中的run方法。
3) 创建Thread子类对象,即创建了线程对象。
4) 调用线程对象start方法:启动线程,调用run方法。
2—实现Runnable接口
1)定义类,实现Runnable接口。
2)覆盖Runnable接口中的run方法。
3)通过Thread类建立线程对象。
4)将Runnable接口的子类对象作为实际参数传递给Thread类的构造方法中。
5)调用Thread类的start方法:开启线程,调用Runnable子类接口的run方法。
【区别】
继承Thread: 线程代码存放Thread子类run方法中。
实现Runnable:线程代码存在接口的子类的run方法。
【实现方法的好处】
1)避免了单继承的局限性
2)多个线程可以共享同一个接口子类的对象,非常适合多个相同线程来处理同一份资源。
编写一个继承Thread类的方式实现多线程的程序。该类MyThread有两个属性,一个字符串WhoAmI代表线程名,一个整数delay代表该线程随机要休眠的时间。构造有参的构造器,线程执行时,显示线程名和要休眠时间。
另外,定义一个测试类TestThread,创建三个线程对象以展示执行情况。
class MyThread extends Thread {
private String whoAmI;
private int delay;
public MyThread(String s, int d) {
whoAmI = s;
delay = d;
}
public void run() {
try {
sleep(delay);
} catch (InterruptedException ie) {
}
System.out.println("Hello!I am" + whoAmI + ",I slept" + delay + "milliseconds");
}
}
public class TestThread {
public static void main(String[] args) {
MyThread t1 = new MyThread("Thread-1", (int) (Math.random() * 100));
MyThread t2 = new MyThread("Thread-2", (int) (Math.random() * 100));
MyThread t3 = new MyThread("Thread-3", (int) (Math.random() * 100));
t1.start();
t2.start();
t3.start();
}
}
public class Test {
public static void main(String[] args) {
MyThread m = new MyThread();
Thread t = new Thread(m);
t.start();
{1}
int j = m.i;
System.out.println(j);
}
}
class MyThread implements Runnable{
int i;
public void run(){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
i=100;
}
}
//在输出前停止主线程,执行副线程
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
public class ThreadPrint extends Thread {
int k = 1;
public void run() {
int i = k;
while (i < 50) {
System.out.println(Thread.currentThread().getName() + "-----" + i);
i += 2;
}
System.out.println(Thread.currentThread().getName() + " end!");
}
public static void main(String[] args) {
ThreadPrint t1 = new ThreadPrint();
ThreadPrint t2 = new ThreadPrint();
t1.k = 1;
t2.k = 2;
t1.start();
t2.start();
}
}
各运行20次,结果i的值等于初始值。
1)启动两个线程对一个数字i操作(10分)
2)其中1个线程每次对i加1(10分)
3)另1个线程每次对i减一(10分)
4)各运行20次,结果i的值等于初始值。(20分)