多线程

1.1.
java中有几种方法可以实现一个线程?用什么关键字修饰同步方法? stop()和suspend()方法为何不推荐使用?
答:有两种实现方法,分别是继承Thread类与实现Runnable接口
用synchronized关键字修饰同步方法
反对使用stop(),是因为它不安全。它会解除由线程获取的所有锁定,而且如果对象处于一种不连贯状态,
那么其他线程能在那种状态下检查和修改它们。结果很难检查出真正的问题所在。suspend()方法容易发生死锁。
调用suspend()的时候,目标线程会停下来,但却仍然持有在这之前获得的锁定。此时,其他任何线程都不能访
问锁定的资源,除非被"挂起"的线程恢复运行。对任何线程来说,如果它们想恢复目标线程,同时又试图
使用任何一个锁定的资源,就会造成死锁。所以不应该使用suspend(),而应在自己的Thread类中置入一个标志,
指出线程应该活动还是挂起。若标志指出线程应该挂起,便用wait()命其进入等待状态。若标志指出线程应当
恢复,则用一个notify()重新启动线程。

1.2.
sleep() 和 wait() 有什么区别?
答:sleep是线程类(Thread)的方法,导致此线程暂停执行指定时间,给执行机会给其他线程,但是监控状态
依然保持,到时后会自动恢复。调用sleep不会释放对象锁。
wait是Object类的方法,对此对象调用wait方法导致本线程放弃对象锁,进入等待此对象的等待锁定池,只有针对
此对象发出notify方法(或notifyAll)后本线程才进入对象锁定池准备获得对象锁进入运行状态。
1.3.
同步和异步有何异同,在什么情况下分别使用他们?举例说明。
答:如果数据将在线程间共享。例如正在写的数据以后可能被另一个线程读到,或者正在读的数据可能已经被另一个
线程写过了,那么这些数据就是共享数据,必须进行同步存取。
当应用程序在对象上调用了一个需要花费很长时间来执行的方法,并且不希望让程序等待方法的返回时,就应该使用
异步编程,在很多情况下采用异步途径往往更有效率。
1.4.
启动一个线程是用run()还是start()?
答:启动一个线程是调用start()方法,使线程所代表的虚拟处理机处于可运行状态,这意味着它可以由JVM调度
并执行。这并不意味着线程就会立即运行。run()方法可以产生必须退出的标志来停止一个线程。
1.5.
当一个线程进入一个对象的一个synchronized方法后,其它线程是否可进入此对象的其它方法?
答:不能,一个对象的一个synchronized方法只能由一个线程访问。
1.6.
请说出你所知道的线程同步的方法?
答:wait():使一个线程处于等待状态,并且释放所持有的对象的lock。
sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要捕捉InterruptedException异常。
notify():唤醒一个处于等待状态的线程,注意的是在调用此方法的时候,并不能确切的唤醒某一个等待状态的
线程,而是由JVM确定唤醒哪个线程,而且不是按优先级。
Allnotity():唤醒所有处入等待状态的线程,注意并不是给所有唤醒线程一个对象的锁,而是让它们竞争。
1.7.
多线程有几种实现方法,都是什么?同步有几种实现方法,都是什么?
答:多线程有两种实现方法,分别是继承Thread类与实现Runnable接口
同步的实现方面有两种,分别是synchronized,wait与notify

1.8.
线程的基本概念、线程的基本状态以及状态之间的关系
答:线程指在程序执行过程中,能够执行程序代码的一个执行单位,每个程序至少都有一个线程,也就是程序本身。
Java中的线程有四种状态分别是:运行、就绪、挂起、结束
1.9.
判断题
1.C 和 Java 都是多线程语言。( )
2.如果线程死亡,它便不能运行。( )
3.在 Java 中,高优先级的可运行线程会抢占低优先级线程。( )
4.程序开发者必须创建一个线程去管理内存的分配。( )
5.一个线程在调用它的 start 方法,之前,该线程将一直处于出生期。( )
6.当调用一个正在进行线程的 stop()方法时,该线程便会进入休眠状态。( )
7.如果线程的 run 方法执行结束或抛出一个不能捕获的例外,线程便进入等待状态。( )
8.一个线程可以调用 yield 方法使其他线程有机会运行。( )

【答案】
1.难度:容易
答案:错误
知识点:C 是单线程语言。
2.难度:容易
答案:正确
知识点:线程死亡就意味着它不能运行。
3.难度:适中
答案:正确
知识点:线程优先级的使用。
4.难度:适中
答案:错误
知识点:Java 提供了一个系统线程来管理内存的分配。
5.难度:容易
答案:正确
知识点:出生期的概念。
6.难度:适中
答案:错误
知识点:应该是 sleep 方法。
7.难度:适中
答案:错误
知识点:如果线程的 run 方法执行结束或抛出一个不能捕获的例外,线程便进入死亡状态。
8.难度:适中
答案:正确
知识点:yield 方法总是让高优先级的就绪线程先运行。
1.10.
选择题
1.Java 语言中提供了一个▁▁线程,自动回收动态分配的内存。
A 异步
B 消费者
C 守护
D 垃圾收集
2.当▁▁方法终止时,能使线程进入死亡状态。
A run
B setPrority
C yield
D sleep
3.用▁▁方法可以改变线程的优先级。
A run
B setPrority
C yield
D sleep
4.线程通过▁▁方法可以使具有相同优先级线程获得处理器。
A run
B setPrority
C yield
D sleep
5.线程通过▁▁方法可以休眠一段时间,然后恢复运行。
A run
B setPrority
C yield
D sleep
6.▁▁方法使对象等待队列的第一个线程进入就绪状态。
A run
B notify
C yield
D sleep
7.方法 resume( )负责重新开始▁▁线程的执行。
A 被 stop( )方法停止
B 被 sleep( )方法停止
C 被 wait( )方法停止
D 被 suspend( )方法停止
8.▁▁方法可以用来暂时停止当前线程的运行。
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( )方法后,当前的线程不能重新开始运行。
1.11.
Java为什么要引入线程机制,线程、程序、进程之间的关系是怎样的?
答:线程可以彼此独立的执行,它是一种实现并发机制的有效手段,可以同时使用多个线程来完成不同的任务,
并且一般用户在使用多线程时并不考虑底层处理的细节。
程序是一段静态的代码,是软件执行的蓝本。进程是程序的一次动态执行过程,即是处于运行过程中的程序。
线程是比进程更小的程序执行单位,一个进程可以启动多个线程同时运行,不同线程之间可以共享相同的内
存区域和数据。多线程程序是运行时间后嗣可能出现在一个进程之内的、有一个以上线程同时运行的情况的程序。
1.12.
Runnable接口包括哪些抽象方法?Thread类有哪些主要域和方法?

答:Runnable接口中仅有run()抽象方法。
Thread类主要域有:MAX_PRIORITY,MIN_PRIORITY,NORM_PRIORITY。
主要方法有start(),run(),sleep(),currentThread(),setPriority(),getPriority(),join()等。
1.13.
创建线程有哪两种方式?试写出每种的具体的流程。比较两种创建方式的不同,哪个更优

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)多个线程可以共享同一个接口子类的对象,非常适合多个相同线程来处理同一份资源。
    1.14.
    编写一个继承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();
    }
    }

1.15.
利用多线程设计一个程序,同时输出 50 以内的奇数和偶数,以及当前运行的线程名。

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(); 
	} 
}

1.16.
写出一个死锁案例?

package com.jp.example3;

public class DeadLock {
	public static String obj1 = new String("obj1");
	public static String obj2 = new String("obj2");
	
	public static void main(String[] args) {
		
		new Thread(new Runnable(){
			@Override
			public void run() {
				while(true){
					synchronized(DeadLock.obj1){
						System.out.println("A");
						synchronized(DeadLock.obj2){
							System.out.println("B");
						}
					}
				}
				
			}
		}).start();
		
		new Thread(new Runnable(){
			@Override
			public void run() {
				while(true){
					synchronized(DeadLock.obj2){
						System.out.println("C");
						synchronized(DeadLock.obj1){
							System.out.println("D");
						}
					}
				}
				
			}
		}).start();
	}
}

1.17.
写出一个生产者消费者案例?

package com.jp.example5;

public class Demo {
	public static void main(String[] args) {
		
		//创建一个店员
		Clerk c = new Clerk();
		
		//创建了两个线程任务
		Producer p = new Producer(c);//生产
		Consumer con = new Consumer(c);//消费
		
		//创建线程
		Thread t1 = new Thread(p);
		Thread t2 = new Thread(con);
		Thread t3 = new Thread(p);
		Thread t4 = new Thread(con);
		
		t1.setName("生产者1");
		t2.setName("消费者2");
		t3.setName("生产者3");
		t4.setName("消费者4");
		
		//开启线程,并且执行线程
		t1.start();
		t2.start();
		t3.start();
		t4.start();
	}
}

//店员
class Clerk{
	int bread;//面包
	
	//生产面包
	public synchronized void add(){
		if(bread>=15){
			//等待
			try {
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}else{
			bread++;
			System.out.println(Thread.currentThread().getName() + ":生产了第" + bread + "个面包");
			notifyAll();
		}
	}
	
	//消费面包
	public synchronized void sale(){
		if(bread <= 0){
			//等待
			try {
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}else{
			System.out.println(Thread.currentThread().getName() + ":消费了第" + bread + "个面包");
			bread--;
			notifyAll();
		}
	}
}

//生产者
class Producer implements Runnable{
	Clerk c;
	public Producer(Clerk c) {
		this.c = c;
	}

	@Override
	public void run() {
		while(true){
			try {
				Thread.sleep(100);
			} catch (InterruptedException e1) {
				e1.printStackTrace();
			}
			//生产面包
			c.add();
		}
	}
 }

//消费者
class Consumer implements Runnable{
	Clerk c;
	public Consumer(Clerk c) {
		this.c = c;
	}
	 
	@Override
	public void run() {
		while(true){
			try {
				Thread.sleep(100);
			} catch (InterruptedException e1) {
				e1.printStackTrace();
			}
			//消费面包
			c.sale();
		}
	}
	 
}
package com.jp.example4;

public class Demo2 {
	public static void main(String[] args) {
		Clerk c = new Clerk();
		Producer p = new Producer(c);
		Consumer con = new Consumer(c);
		
		Thread t1 = new Thread(p);
		Thread t3 = new Thread(p);
		Thread t2 = new Thread(con);
		Thread t4 = new Thread(con);
		t1.setName("生产者1");
		t2.setName("消费者1");
		t3.setName("生产者2");
		t4.setName("消费者2");
		t1.start();
		t2.start();
		t3.start();
		t4.start();
	}
}
class Clerk{
	int bread;
	
	public synchronized void add(){
		if(bread>=15){
			//停下来,等着
			try {
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}else{
			bread++;
			System.out.println(Thread.currentThread().getName() + ": 生产了第" + bread + "个面包");
			notify();
		}
	}
	
	public synchronized void sale(){
		if(bread <= 0){
			//等着
			try {
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}else{
			System.out.println(Thread.currentThread().getName() + ": 消费了第" + bread + "个面包");
			bread--;
			notify();
		}
	}
}

class Producer implements Runnable{
	Clerk c;
	
	public Producer(Clerk c) {
		this.c = c;
	}


	@Override
	public void run() {
		while(true){
			try {
				Thread.sleep(100);
			} catch (InterruptedException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
			c.add();
//			synchronized (c) {
//				if(c.bread>=15){
//					//停下来,等着
//					try {
//						c.wait();
//					} catch (InterruptedException e) {
//						e.printStackTrace();
//					}
//				}else{
//					c.bread++;
//					System.out.println(Thread.currentThread().getName() + ": 生产了第" + c.bread + "个面包");
//					c.notify();
//				}
//			}
		}
	}
}


class Consumer implements Runnable{
	Clerk c;
	public Consumer(Clerk c) {
		this.c = c;
	}

	
	@Override
	public void run() {
		while(true){
			try {
				Thread.sleep(100);
			} catch (InterruptedException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
			c.sale();
//			synchronized (c) {
//				if(c.bread <= 0){
//					//等着
//					try {
//						c.wait();
//					} catch (InterruptedException e) {
//						e.printStackTrace();
//					}
//				}else{
//					System.out.println(Thread.currentThread().getName() + ": 消费了第" + c.bread + "个面包");
//					c.bread--;
//					c.notify();
//				}
//			}
			
		}
	}
}

简述synchronized和java.util.concurrent.locks.Lock的异同 ?
答:主要相同点:Lock能完成synchronized所实现的所有功能
主要不同点:Lock有比synchronized更精确的线程语义和更好的性能。synchronized会自动释放锁,而Lock一定要求
程序员手工释放,并且必须在finally从句中释放。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值