`

java线程15个经典问题(一)

阅读更多

(1)现在有T1、T2、T3三个线程,你怎样保证T2在T1执行完后执行,T3在T2执行完后执行?

 

public class Test {  
	
    @SuppressWarnings("static-access")  
    public static void main(String[] args) throws InterruptedException {  
        Thread t1 = new Thread("1");  
        Thread t2 = new Thread("2");  
        Thread t3 = new Thread("3");  
        t1.start();  
        t1.sleep(1000);
        t1.join();
        System.out.println(t1.getName());
        
        t2.start();  
        t2.sleep(1000);  
        t2.join();  
        System.out.println(t2.getName());
        
        t3.start();  
        t3.join();  
        System.out.println(t3.getName());
      
    }  
      
}  

(2)请问java中的lock和synchronized区别是什么?

假设该场景下,ReentrantLock 拥有Synchronized相同的并发性和内存语义,此外还多了 锁投票,定时锁等候和中断锁等候线程A和B都要获取对象O的锁定,假设A获取了对象O锁,B将等待A释放对O的锁定

如果使用 synchronized ,如果A不释放,B将一直等下去,不能被中断
如果使用ReentrantLock,如果A不释放,可以使B在等待了足够长的时间以后,中断等待,而干别的事情 ReentrantLock获取锁定与三种方式:
    a)  lock(), 如果获取了锁立即返回,如果别的线程持有锁,当前线程则一直处于休眠状态,直到获取锁
    b) tryLock(), 如果获取了锁立即返回true,如果别的线程正持有锁,立即返回false;
    c)tryLock(long timeout,TimeUnit unit), 如果获取了锁定立即返回true,如果别的线程正持有锁,会等待参数给定的时间,在等待的过程中,如果获取了锁定,就返回true,如果等待超时,返回false;
    d) lockInterruptibly: 如果获取了锁定立即返回,如果没有获取锁定,当前线程处于休眠状态,直到或者锁定,或者当前线程被别的线程中断
2、synchronized是在JVM层面上实现的,不但可以通过一些监控工具监控synchronized的锁定,而且在代码执行时出现异常,JVM会自动释放锁定,但是使用Lock则不行,lock是通过代码实现的,要保证锁定一定会被释放,就必须将unLock()放到finally{}中
3、在资源竞争不是很激烈的情况下,Synchronized的性能要优于ReetrantLock,但是在资源竞争很激烈的情况下,Synchronized的性能会下降几十倍,但是ReetrantLock的性能能维持常态;

(3)在java中wait和sleep方法的不同?

通常会在电话面试中经常被问到的Java线程面试问题。最大的不同是在等待时wait会释放锁,而sleep一直持有锁。Wait通常被用于线程间交互,sleep通常被用于暂停执行。

wait()方法用于协调多个线程对共享数据的存取,所以必须在Synchronized语句块内使用wait方法

调用sleep()和yield()的时候锁并没有被释放,而调用wait()将释放锁。这样另一个任务(线程)可以获得当前对象的锁,从而进入它的synchronized方法中。可以通过notify()/notifyAll(),或者时间到期,从wait()中恢复执行。
只能在同步控制方法或同步块中调用wait()、notify()和notifyAll()。如果在非同步的方法里调用这些方法,在运行时会抛出IllegalMonitorStateException异常。

private int num;
	private Object lock;

	public OutputThread(int num, Object lock) {
		super();
		this.num = num;
		this.lock = lock;
	}

	public void run() {
		try {
			while (true) {
				synchronized (lock) {
					lock.notifyAll();
					lock.wait();
					System.out.println(num);
				}
			}
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

 

(4)用Java实现阻塞队列?

阻塞队列是Java5线程新特征中的内容,Java定义了阻塞队列的接口 java.util.concurrent.BlockingQueue,阻塞队列的概念是,一个指定长度的队列,如果队列满了,添加新元素的操作会被阻 塞等待,直到有空位为止。同样,当队列为空时候,请求队列元素的操作同样会阻塞等待,直到有可用元素为止。有了这样的功能,就为多线程的排队等候的模型实现开辟了便捷通道,非常有用。java.util.concurrent.BlockingQueue继承了java.util.Queue接口,可以参看API文档。

简单例子:没有用线程,容易理解

public class Test {
        public static void main(String[] args) throws InterruptedException {
                BlockingQueue bqueue = new ArrayBlockingQueue(20);
                for (int i = 0; i < 30; i++) {
                        //将指定元素添加到此队列中,如果没有可用空间,将一直等待(如果有必要)。
                        bqueue.put(i);
                        System.out.println("向阻塞队列中添加了元素:" + i);
                }
                System.out.println("程序到此运行结束,即将退出----");
        }
}

 

复杂例子用了线程,阻塞的生产者模式---消费者模式,线程同步的

此段转自:http://www.cnblogs.com/dolphin0520/p/3932906.html

public class Test {
    private int queueSize = 10;
    private ArrayBlockingQueue<Integer> queue = new ArrayBlockingQueue<Integer>(queueSize);
     
    public static void main(String[] args)  {
        Test test = new Test();
        Producer producer = test.new Producer();
        Consumer consumer = test.new Consumer();
         
        producer.start();
        consumer.start();
    }
     
    class Consumer extends Thread{
         
        @Override
        public void run() {
            consume();
        }
         
        private void consume() {
            while(true){
                try {
                    queue.take();
                    System.out.println("从队列取走一个元素,队列剩余"+queue.size()+"个元素");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
     
    class Producer extends Thread{
         
        @Override
        public void run() {
            produce();
        }
         
        private void produce() {
            while(true){
                try {
                    queue.put(1);
                    System.out.println("向队列取中插入一个元素,队列剩余空间:"+(queueSize-queue.size()));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

      在并发编程中,一般推荐使用阻塞队列,这样实现可以尽量地避免程序出现意外的错误。

  阻塞队列使用最经典的场景就是socket客户端数据的读取和解析,读取数据的线程不断将数据放入队列,然后解析线程不断从队列取数据解析。还有其他类似的场景,只要符合生产者-消费者模型的都可以使用阻塞队列。

几种主要的阻塞队列?

       自从Java 1.5之后,在java.util.concurrent包下提供了若干个阻塞队列,主要有以下几个:
  ArrayBlockingQueue:基于数组实现的一个阻塞队列,在创建ArrayBlockingQueue对象时必须制定容量大小。并且可以指定公平性与非公平性,默认情况下为非公平的,即不保证等待时间最长的队列最优先能够访问队列。
  LinkedBlockingQueue:基于链表实现的一个阻塞队列,在创建LinkedBlockingQueue对象时如果不指定容量大小,则默认大小为Integer.MAX_VALUE。
  PriorityBlockingQueue:以上2种队列都是先进先出队列,而PriorityBlockingQueue却不是,它会按照元素的优先级对元素进行排序,按照优先级顺序出队,每次出队的元素都是优先级最高的元素。注意,此阻塞队列为无界阻塞队列,即容量没有上限(通过源码就可以知道,它没有容器满的信号标志),前面2种都是有界队列。
  DelayQueue:基于PriorityQueue,一种延时阻塞队列,DelayQueue中的元素只有当其指定的延迟时间到了,才能够从队列中获取到该元素。DelayQueue也是一个无界队列,因此往队列中插入数据的操作(生产者)永远不会被阻塞,而只有获取数据的操作(消费者)才会被阻塞。

(5)为什么我们调用start()方法时会执行run()方法,为什么我们不能直接调用run()方法?

这个问题的回答应该是这样的,当你调用start()方法时你将创建新的线程,并且执行在run()方法里的代码。但是如果你直接调用run()方法,它不会创建新的线程也不会执行调用线程的代码。

分享到:
评论

相关推荐

    线程 JAVA java线程 java线程第3版 java线程第2版第3版合集

    电子书相关:包含4个有关JAVA线程的电子书(几乎涵盖全部有关线程的书籍) OReilly.Java.Threads.3rd.Edition.Sep.2004.eBook-DDU Java Thread Programming (Sams) java线程第二版中英文 java线程第二版中英文 ...

    java多线程经典案例

    而线程通信可能体现在当一个线程完成转账后通知另一个线程继续执行的场景。线程阻塞则可能出现在账户余额不足,需要等待外部充值后再继续转账的情况。 通过分析并实践`threadTest`案例,我们可以深入理解Java多线程...

    java一个多线程的经典例子

    根据提供的文件信息,我们可以归纳出以下关于Java多线程的经典示例中的关键知识点: ### Java多线程实现方式 在Java中,实现多线程有两种主要的方法:通过继承`Thread`类或者实现`Runnable`接口。 #### 继承...

    java多线程Demo

    Java线程有10个优先级(MIN_PRIORITY, NORM_PRIORITY, MAX_PRIORITY),默认优先级是NORM_PRIORITY。但是,线程优先级并不保证绝对的执行顺序,操作系统调度策略可能影响实际执行顺序。 7. join()方法: 一个线程...

    JAVA单线程多线程

    在Java编程环境中,单线程指的是程序执行过程中只有一个线程在运行。这意味着任何时刻只能执行一个任务,上一个任务完成后才会进行下一个任务。单线程模型简化了程序设计,降低了程序复杂度,使得开发者可以更专注于...

    java 线程工具类 java 线程工具类

    java 线程工具类 java 线程工具类java 线程工具类 java 线程工具类java 线程工具类 java 线程工具类java 线程工具类 java 线程工具类java 线程工具类 java 线程工具类java 线程工具类 java 线程工具类java 线程工具...

    java线程.pdf

    Java线程是Java编程中非常重要的一个概念,它可以帮助开发者实现多任务并行处理,提高程序的执行效率。理解线程的创建、生命周期管理以及线程间的同步和通信机制对于开发高质量的Java应用至关重要。希望以上内容能够...

    Java线程.ppt

    Java线程是Java编程中的重要概念,特别是在多核处理器和并发处理中不可或缺。Java线程允许程序在同一时间执行多个不同的任务,从而提高了程序的效率和响应性。在燕山大学信息学院计算机系的课程中,李峰教授讲解了...

    java程序 两个线程实现学生成绩的读写

    Java程序中的多线程技术是实现并发操作的关键,尤其在处理并发读写数据时,如在本例中,我们有两条线程分别负责读取和写入学生的成绩...通过学习这个程序,我们可以深入理解Java线程的使用以及并发编程中的核心概念。

    java多线程经典讲义

    创建Java线程主要有两种方式: 1. 继承Thread类:首先定义一个类继承自Thread,然后重写run()方法。在main方法中创建该类的实例并调用start()方法启动线程。这种方式的缺点是限制了类的继承,因为Java不支持多重...

    Java线程详解大全

    Java线程是并发编程的核心部分,它允许程序在同一时间执行多个独立的任务,从而提高系统效率和响应速度。本文将深入探讨Java线程的概念、生命周期、实现方式以及相关的同步机制。 首先,理解线程的基本概念至关重要...

    java线程分析工具TDA

    Java线程分析是Java开发中的重要环节,尤其是在处理性能优化、死锁排查或者并发问题时。TDA(Thread Dump Analyzer)是一款强大的Java线程分析工具,它能够帮助开发者深入理解应用在运行时的线程状态,包括线程的...

    Java线程使用教程

    Java线程是Java编程语言中的一个核心概念,它允许程序同时执行多个任务,极大地提高了程序的并发性和效率。本教程将深入探讨Java线程的使用,帮助开发者掌握这一关键技术。 一、线程基础 1. **线程的概念**:线程...

    JAVA线程dump的分析

    在实际运行中,往往一次dump的信息,还不足以确认问题,建议产生三次dump信息,如果每次dump都指向同一个问题,我们才确定问题的典型性。 JAVA线程dump分析的步骤包括: 1. 了解线程状态:线程可以是Runnable、...

    Java线程状态流转图

    Java线程状态流转图是一种用于描述Java线程生命周期中不同的状态和状态转换的图形表示方式。该图形展示了Java线程从创建到终止的整个生命周期,并详细介绍了每种状态的特点和转换规则。 NEW(初始化状态) 在Java...

    java经典多线程面试题

    - CountDownLatch是一个同步辅助类,它允许一个或多个线程等待直到在其他线程中执行的一组操作完成。 这些面试题涵盖了Java多线程编程的基础知识、同步机制、线程间通信以及并发集合类等多个方面。在准备面试时,...

    Java多线程知识点总结

    Java多线程是Java编程语言中一个非常重要的概念,它允许开发者在一个程序中创建多个执行线程并行运行,以提高程序的执行效率和响应速度。在Java中,线程的生命周期包含五个基本状态,分别是新建状态(New)、就绪...

    java 多线程:哲学家思考问题

    java 多线程 哲学家思考问题 java 多线程 哲学家思考问题 ...java 多线程 哲学家思考问题java 多线程 哲学家思考问题java 多线程 哲学家思考问题java 多线程 哲学家思考问题 java 多线程 哲学家思考问题

    java线程深入解析

    本文将深入解析Java线程的相关知识点,包括线程的定义、创建、状态管理、线程同步和安全问题。 1. **线程定义** 在Java中,线程是进程中的单一顺序控制流,是程序执行的基本单元。线程在进程的上下文中运行,共享...

    java线程实例 各种小Demo

    Java线程有五种状态:新建、可运行、运行、阻塞和终止。可以通过Thread类的getState()方法查看线程状态。线程的控制包括: - sleep():使当前线程进入休眠状态,指定时间后自动唤醒。 - join():让当前线程等待另一...

Global site tag (gtag.js) - Google Analytics