1、java中多线程同步是什么?
答:在多线程的程序下,同步能控制对共享资源的访问,如果没有同步,当一个java线程在修改一个共享变量时,另一个java线程正在使用或者更新同一个变量这样容易导致程序出现错误的结果。
2、线程有几种?有哪些实现的方法?
答:多线程有两种实现方法,一种是继承Thread类另一种是实现Runable接口。
3、Thread.start()和Thread.run()有什么区别?
答、start()方法被用来启动新创建的线程,而且start()内部调用了run()方法,这和直接调用run()方法的效果不一样。当你调用run()方法的时候,只会是在原来的线程中调用,没有新的线程启动,start()方法才会启动新线程。
4、为什么需要run()和start()两种方法?我们可以只用run()完成任务吗?
答:我们需要run()&start()这两个方法是因为JVM创建一个单独的线程不同于普通方法的调用,所以这项工作由线程的start方法来完成,start由本地方法实现,需要显示地被调用,使用这俩个方法的另外一个好处是任何一个对象都可以作为线程运行,只要实现了Runnable接口,这就避免因继承了Thread类而造成的Java的多继承问题。
5、Sleep(),suspend(),wait()有什么区别?
答:sleep()是一个静态方法。这意味着只对当前线程有效,一个常见的错误是调用t.sleep(),(这里的t是一个不同于当前线程的线程)。即便是执行t.sleep(),也是当前线程进入睡眠,而不是t线程。t.suspend()是过时的方法,使用suspend()导致线程进入停滞状态,该线程会一直持有对象的监视器,suspend()容易引起死锁问题。
object.wait()使当前线程出于“不可运行”状态,和sleep()不同的是wait是object的方法而不是thread。调用object.wait()时,线程先要获取这个对象的对象锁,当前线程必须在锁对象保持同步,把当前线程添加到等待队列中,随后另一线程可以同步同一个对象锁来调用object.notify(),这样将唤醒原来等待中的线程,然后释放该锁。基本上wait()/notify()与sleep()/interrupt()类似,只是前者需要获取对象锁。
6、在一个对象上两个线程可以调用两个不同的同步实例方法吗?
答:不能,因为一个对象已经同步了实例方法,线程获取了对象的对象锁。所以只有执行完该方法释放对象锁后才能执行其它同步方法。
7、什么是死锁?
答:死锁就是两个或两个以上的线程被无限的阻塞,线程之间相互等待所需资源。这种情况可能发生在当两个线程尝试获取其它资源的锁,而每个线程又陷入无限等待其它资源锁的释放,除非一个用户进程被终止
8、线程和进程有什么区别?
答:线程是进程的子集,一个进程可以有很多线程,每条线程并行执行不同的任务。不同的进程使用不同的内存空间,而所有的线程共享一片相同的内存空间。别把它和栈内存搞混,每个线程都拥有单独的栈内存用来存储本地数据。
9、什么是线程安全?Vector是一个线程安全类吗?
答:如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。一个线程安全的计数器类的同一个实例对象在被多个线程使用的情况下也不会出现计算失误。很显然你可以将集合类分成两组,线程安全和非线程安全的。Vector 是用同步方法来实现线程安全的, 而和它相似的ArrayList不是线程安全的。
10、Java中如何停止一个线程?
答:Java提供了很丰富的API但没有为停止线程提供API。JDK 1.0本来有一些像stop(), suspend() 和 resume()的控制方法但是由于潜在的死锁威胁因此在后续的JDK版本中他们被弃用了,之后Java API的设计者就没有提供一个兼容且线程安全的方法来停止一个线程。当run() 或者 call() 方法执行完的时候线程会自动结束,如果要手动结束一个线程,你可以用volatile 布尔变量来退出run()方法的循环或者是取消任务来中断线程
11、Java中notify 和 notifyAll有什么区别?
答:notify()方法不能唤醒某个具体的线程,所以只有一个线程在等待的时候它才有用武之地。而notifyAll()唤醒所有线程并允许他们争夺锁确保了至少有一个线程能继续运行。
12、为什么wait和notify方法要在同步块中调用?
答:主要是因为Java API强制要求这样做,如果你不这么做,你的代码会抛出IllegalMonitorStateException异常。还有一个原因是为了避免wait和notify之间产生竞态条件。
13、 什么是线程池? 为什么要使用它?
答:创建线程要花费昂贵的资源和时间,如果任务来了才创建线程那么响应时间会变长,而且一个进程能创建的线程数有限。为了避免这些问题,在程序启动的时候就创建若干线程来响应处理,它们被称为线程池,里面的线程叫工作线程。从JDK1.5开始,Java API提供了Executor框架让你可以创建不同的线程池。比如单线程池,每次处理一个任务;数目固定的线程池或者是缓存线程池(一个适合很多生存期短的任务的程序的可扩展线程池)
14、 如何写代码来解决生产者消费者问题?(多线程的应用问题,经典题目)
答:在现实中你解决的许多线程问题都属于生产者消费者模型,就是一个线程生产任务供其它线程进行消费,你必须知道怎么进行线程间通信来解决这个问题。比较低级的办法是用wait和notify来解决这个问题,比较赞的办法是用Semaphore 或者 BlockingQueue来实现生产者消费者模型,
15、如何避免死锁?
答:避免死锁最简单的方法就是阻止循环等待条件,将系统中所有的资源设置标志位、排序,规定所有的进程申请资源必须以一定的顺序(升序或降序)做操作来避免死锁。
16、Thread类中的yield方法有什么作用?
答:Yield方法可以暂停当前正在执行的线程对象,让其它有相同优先级的线程执行。它是一个静态方法而且只保证当前线程放弃CPU占用而不能保证使其它线程一定能占用CPU,执行yield()的线程有可能在进入到暂停状态后马上又被执行
17、Java中你怎样唤醒一个阻塞的线程?
答:suspend()、resume()可以唤醒,但是会出现死锁的现象。
18、写两个线程,一个线程打印 1~52,另一个线程打印字母A-Z。打印顺序为12A34B56C……5152Z。要求用线程间的通信。
class Test{
public static void main(String[] args) {
Printer p = new Printer();
Thread t1 = new NumberPrinter(p);
Thread t2 = new LetterPrinter(p);
t1.start();
t2.start();
}
}
class Printer{
private int index = 1;//设为1,方便计算3的倍数
//打印数字的构造方法,每打印两个数字,等待打印一个字母
public synchronized void print(int i){
while(index%3==){try{wait();}catch(Exception e){}}
System.out.print(” ̶+i);
index++;
notifyAll();
}
//打印字母,每打印一个字母,等待打印两个数字
public synchronized void print(char c){
while(index%3!=){try{wait();}catch(Exception e){}}
System.out.print(” ̶+c);
index++;
notifyAll();
}
}
//打印数字的线程
class NumberPrinter extends Thread{
private Printer p;
public NumberPrinter(Printer p){this.p = p;}
public void run(){
for(int i = 1; i<=52; i++){
p.print(i);
}
}
}
//打印字母的线程
class LetterPrinter extends Thread{
private Printer p;
public LetterPrinter(Printer p){this.p = p;}
public void run(){
for(char c=’A'; c<=’Z'; c++){
p.print(c);
}
}
}
19、生产者消费者问题编程,用同步机制实现。
答:public class ThreadDemo4 {
private static boolean flags =false;
public static void main(String[] args){
class Goods{
private String name;
private int num;
public synchronized void produce(String name){
if(flags)
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
this.name =name+"编号:"+num++;
System.out.println("生产了...."+this.name);
flags =true;
notifyAll();
}
public synchronized void consume(){
if(!flags)
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("消费了******"+name);
flags =false;
notifyAll();
}
}
final Goods g =new Goods();
new Thread(new Runnable(){
public void run(){
while(true){
g.produce("商品");
}
}
}).start();
new Thread(new Runnable(){
public void run(){
while(true){
g.consume();
}
}
}).start();
}
}
20、模拟3个人排除买票,张某、李某和赵某买电影票,售票员只有3张五元的钱,电影票5元一张。张某拿20元一张的RMB排在李某的前面,李某排在赵某的前面拿一张10元的RMB买票,赵某拿一张5元的RMB买票。
package week14_2;
import java.awt.BorderLayout;
import java.awt.event.*;
import javax.swing.*;
public class Ticket
{
public static void main(String[] args)
{
new MyFrame();
}
}
class MyFrame extends JFrame implements Runnable,ActionListener
{
TicketSeller seller;
Thread buyer1,buyer2,buyer3;
static JTextArea text;
JButton start = new JButton("排队买票");
MyFrame()
{
seller = new TicketSeller();
buyer1 = new Thread(this);
buyer2 = new Thread(this);
buyer3 = new Thread(this);
text = new JTextArea(10,30);
start.addActionListener(this);
add(text,BorderLayout.CENTER);
add(start,BorderLayout.NORTH);
setVisible(true);
setSize(360,300);
validate();
}
public void actionPerformed(ActionEvent e)
{
try
{
buyer1.start();
buyer2.start();
buyer3.start();
}
catch(Exception exp) {}
}
public void run() {
if(Thread.currentThread() == buyer1)
{
seller.rule(20);
}
else if(Thread.currentThread() == buyer2)
{
seller.rule(10);
}
else if(Thread.currentThread() == buyer3)
{
seller.rule(5);
}
}
}
class TicketSeller
{
int money5=3, money10=0, money20=0;
String s=null;
public synchronized void rule(int money)
{
if(money == 5)//不用等待
{
money5++;
s = "给你入场券,你的钱正好。";
MyFrame.text.append("\n"+s);
}
else if(money == 20)
{
while(money5 < 3)
{
try
{
wait();//没有零钱,等待
}
catch(InterruptedException e){}
}
money5 = money5-3;
money20++;
s = "给你入场券,你给我20元,找你15元。";
MyFrame.text.append("\n"+s);
}
else if(money == 10)
{
while(money5 < 1)
{
try
{
wait();//没有零钱,等待
}
catch(InterruptedException e){}
}
money5 = money5-1;
money10++;
s = "给你入场券,你给我10元,找你5元。";
MyFrame.text.append("\n"+s);
}
notifyAll();
}
}