多线程的问题

来源:互联网 发布:暴走漫画淘宝旗舰店 编辑:程序博客网 时间:2024/05/02 00:33

1:线程和进程的区别:一个进程是一个独立的运行环境,可以说是一个程序或者是一个应用,而线程只是进程的一个任务,一个进程包含多个线程,线程需要较少的资源创建和进驻在进程中,并且可以共享进程的资源

2:多线程的好处:在多线程程序中,多个线程并发执行可以有效的提高CPU的资源使用,cpu不会因为么个线程需要等待资源而进去空闲状态,多个线程共享堆内存,因此创建多个线程去执行一些任务比创建多个进程更好。

3:用户线程和守护线程有什么区别:

当我们用java程序创建一个线程,它就被成为用户线程。一个守护线程是在后台运行并且不会阻止JVM终止的线程。当用户线程全部终止,守护线程也就自动终止啦,守护线程的作用就是为其他线程服务的,比如说gc线程。唯一的区别就是在于:jvm的离开,用户线程全部撤离,jvm也就退出啦

   守护线程并非虚拟机内部可以提供,用户也可以自行的设定守护线程,方法:setDaemon(boolean on) ;但是有几点需要注意:

1:thread.setDaemon(true)必须在thread.start()之前设置,否则会跑出一个IllegalThreadStateException异常。你不能把正在运行的常规线程设置为守护线程。  (备注:这点与守护进程有着明显的区别,守护进程是创建后,让进程摆脱原会话的控制+让进程摆脱原进程组的控制+让进程摆脱原控制终端的控制;所以说寄托于虚拟机的语言机制跟系统级语言有着本质上面的区别)

在Daemon线程中产生的新线程也是Daemon的。  (这一点又是有着本质的区别了:守护进程fork()出来的子进程不再是守护进程,尽管它把父进程的进程相关信息复制过去了,但是子进程的进程的父进程不是init进程,所谓的守护进程本质上说就是“父进程挂掉,init收养,然后文件0,1,2都是/dev/null,当前目录到/”)

不是所有的应用都可以分配给Daemon线程来进行服务,比如读写操作或者计算逻辑。因为在Daemon Thread还没来的及进行操作时,虚拟机可能已经退出了。



class TestRunnable implements Runnable{  

    public void run(){  

               try{  

                  Thread.sleep(1000);//守护线程阻塞1秒后运行  

                  File f=new File("daemon.txt");  

                  FileOutputStream os=new FileOutputStream(f,true);  

                  os.write("daemon".getBytes());  

           }  

               catch(IOException e1){  

          e1.printStackTrace();  

               }  

               catch(InterruptedException e2){  

                  e2.printStackTrace();  

           }  

    }  

}  

public class TestDemo2{  

    public static void main(String[] args) throws InterruptedException  

    {  

        Runnable tr=new TestRunnable();  

        Thread thread=new Thread(tr);  

                thread.setDaemon(true); //设置守护线程  

        thread.start(); //开始执行分进程  

    }  

}  

运行结果:文件daemon.txt中没有"daemon"字符串。

但是如果把thread.setDaemon(true); //设置守护线程注释掉,文件daemon.txt是可以被写入daemon字符串的


4:如何创建一个新的线程:实现runnable接口,继承Thread类,实现Callable接口通过FutureTask包装器来创建Thread线程、使用ExecutorService、Callable、Future实现有返回结果的多线程。

5:可以直接调用Thread类的run()方法吗?

可以  但是调用之后和普通的方法一样,为了在新的线程里面执行代码必须使用thread.start();

6.为什么线程通信的方法wait(), notify()和notifyAll()被定义在Object类里?

Java的每个对象中都有一个锁(monitor,也可以成为监视器) 并且wait(),notify()等方法用于等待对象的锁或者通知其他线程对象的监视器可用。在Java的线程中并没有可供任何对象使用的锁和同步器。这就是为什么这些方法是Object类的一部分,这样Java的每一个类都有用于线程间通信的基本方法

7 为什么wait(), notify()和notifyAll()必须在同步方法或者同步块中被调用?

当一个线程需要调用对象的wait()方法的时候,这个线程必须拥有该对象的锁,接着它就会释放这个对象锁并进入等待状态直到其他线程调用这个对象上的notify()方法。同样的,当一个线程需要调用对象的notify()方法时,它会释放这个对象的锁,以便其他在等待的线程就可以得到这个对象锁。由于所有的这些方法都需要线程持有对象的锁,这样就只能通过同步来实现,所以他们只能在同步方法或者同步块中被调用。

8.如何确保线程安全?

在Java中可以有很多方法来保证线程安全——同步,使用原子类(atomic concurrent classes),实现并发锁,使用volatile关键字,使用不变类和线程安全类

4. 什么是阻塞队列?如何使用阻塞队列来实现生产者-消费者模型?

java.util.concurrent.BlockingQueue的特性是:当队列是空的时,从队列中获取或删除元素的操作将会被阻塞,或者当队列是满时,往队列里添加元素的操作会被阻塞。

阻塞队列不接受空值,当你尝试向队列中添加空值的时候,它会抛出NullPointerException。

阻塞队列的实现都是线程安全的,所有的查询方法都是原子的并且使用了内部锁或者其他形式的并发控制。

BlockingQueue 接口是java collections框架的一部分,它主要用于实现生产者-消费者问题。











原创粉丝点击