java3线程答案

来源:互联网 发布:yum 安装vim 编辑:程序博客网 时间:2024/05/21 21:36

22.JNInative是方法修饰符。Native方法是由另外一种语言(如c/c++,FORTRAN,汇编)实现的本地方法。

1)、继承Thread类实现多线程

继承Thread类的方法尽管被我列为一种多线程实现方式,但Thread本质上也是实现了Runnable接口的一个实例,它代表一个线程的实例,并且,启动线程的唯一方法就是通过Thread类的start()实例方法。start()方法是一个native方法,它将启动一个新线程,并执行run()方法。这种方式实现多线程很简单,通过自己的类直接extend Thread,并复写run()方法,就可以启动新线程并执行自己定义的run()方法。例如

  1. ublic class MyThread extends Thread {  
  2.   public void run() {  
  3.    System.out.println("MyThread.run()");  
  4.   }  
  5. }  
  1. MyThread myThread1 = new MyThread();  
  2. MyThread myThread2 = new MyThread();  
  3. myThread1.start();  
  4. myThread2.start();  
2)实现Runnable接口方式实现多线程

  1. public class MyThread extends OtherClass implements Runnable {  
  2.   public void run() {  
  3.    System.out.println("MyThread.run()");  
  4.   }  
  5. }  
为了启动MyThread,需要首先实例化一个Thread,并传入自己的MyThread实例:
[java] view plain copy
  1. MyThread myThread = new MyThread();  
  2. Thread thread = new Thread(myThread);  
  3. thread.start();  
3)类似的,无返回值的任务必须Runnable接口,可返回值的任务必须实现Callable接口执行Callable任务后,可以获取一个Future的对象,在该对象上调用get就可以获取到Callable任务返回的Object了,再结合线程池接口ExecutorService就可以实现传说中有返回结果的多线程了,ExecutoreService提供了submit()方法,传递一个Callable,或Runnable,返回Future。

23.线程的状态转换


(一). 等待阻塞运行(running)的线程执行o.wait()方法,JVM会把该线程放入等待队列(waitting queue)中。由于notify()只是唤醒一个线程,但我们由不能确定具体唤醒的是哪一个线程,也许我们需要唤醒的线程不能够被唤醒,因此在实际使用时,一般都用notifyAll()方法,唤醒有所线程)

(二). 同步阻塞运行(running)的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池(lock pool)中。当线程刚进入可运行状态(注意,还没运行),发现将要调用的资源被synchroniza(同步),获取不到锁标记,将会立即进入锁池状态,

(三). 其他阻塞运行(running)的线程执行Thread.sleep(long ms)或t.join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入可运行(runnable)状态。

线程同步方法:synchronize与wait-notify

synchronize与lock:自动与手动释放锁

sleep是线程类不会释放锁对象

wait是Object类方法会释放锁对象

24.如何停止一个线程

使用interrupt方法终止线程 

(1)线程处于阻塞状态,如使用了sleep方

法。 

    (2)使用while(!isInterrupted())

{……}来判断线程是否被中断。 

    在第一种情况下使用interrupt方法,sleep

方法将抛出一个InterruptedException例外,

而在第二种情况下线程将直接退出



1 )处于运行状态的线程停止:


线程需要通过设置停止变量的方式


2)处于可中断等待线程的停止:线程调用了sleepwait方法,这些方法可抛出InterruptedException则可以通过调用Threadinterrupt方法让等待方法抛出InterruptedException异常,然后在循环外截获并处理异常


3) 处于IO阻塞状态线程的停止:线程调用了IOread操作或者socketaccept操作,处于阻塞状态。JavaInterruptableChanel接口提供了这样的机制



25.如何保证线程安全

不要跨线程访问共享变量


使共享变量是final类型的


将共享变量的操作加上同步


volatile声明的数值类型变量进行运算, 往往是不安全的(volatile只能保证可见性,不能保证原子性

当一个线程请求获得它自己占有的锁时(同一把锁的嵌套使用), 我们称该锁为可重入锁

 提供了可重入锁的java实现-ReentrantLock.  每个共享变量,都应该由一个唯一确定的锁保护.创建与变量相同数目的ReentrantLock, 使他们负责每个变量的线程安全.

使用ThreadLocal变量确保线程封闭性(封闭线程往往是比较安全的, 但一定程度上会造成性能损耗)封闭对象的例子在实际使用过程中

在并发编程中, 需要容器支持的时候, 优先考虑使用jdk并发容器(ConcurrentHashMap, ConcurrentLinkedQueue, CopyOnWriteArrayList.但是他们支持的并发实现并不一定意味着操作的原子性,他们只是保证数据结构不被破坏

http://blog.csdn.net/fp196391196391/article

/details/39493761


26.Synchronized如何使用

1)方法声明时使用,放在范围操作符(public等)之后,返回类型声明(void等)之前.这时,线程获得的是成员锁,即一次只能有一个线程进入该方法,其他线程要想在此时调用该方法,只能排队等候,当前线程(就是在synchronized方法内部的线程)执行完该方法后,别的线程才能进入.

 public synchronized void synMethod() {
        
//方法体
      }

2)对某一代码块使用,synchronized后跟括号,括号里是变量,这样,一次只有一个线程进入该代码块.此时,线程获得的是成员锁

public int synMethod(int a1){
        synchronized(a1) 
{
          
//一次只能有一个线程进入
        }

      }

3)synchronized后面括号里是一对象,此时,线程获得的是对象锁

public void run() {
    synchronized (
this{
      System.
out.println(Thread.currentThread().getName());
    }

4) synchronized后面括号里是类,此时,线程获得的是对象锁

public ArrayWithLockOrder(int[] a)
  
{
    arr 
= a;
    synchronized(ArrayWithLockOrder.
class{//-----这里
      num_locks++;             // 锁数加 1。

      lock_order 
= num_locks;  // 为此对象实例设置唯一的 lock_order。
    }



27.

lock和synchronized关键词的区别

synchronized是在JVM层面上实现的,不但可以通过一些监控工具监控synchronized的锁定,而且在代码执行时出现异常,JVM会自动释放锁定,但是使用Lock则不行,lock是通过代码实现的,要保证锁定一定会被释放,就必须将unLock()放到finally{}中
在资源竞争不是很激烈的情况下,Synchronized的性能要优于ReetrantLock,但是在资源竞争很激烈的情况下,Synchronized的性能会下降几十倍,但是ReetrantLock的性能能维持常态;
28.sleep和wait的区别


这两个方法来自不同的类分别是,sleep来


自Thread类,和wait来自Object类。


最主要sleep方法没有释放锁,而wait方


法释放了锁,


使用范围:wait,notify和notifyAll只能

在同步控制方法或者同步控制块里面使用,

而sleep可以在任何地方使用 


29.守护进程:


守护线程:守护线程则是用来服务用户线程

的,如果没有其他用户线程在运行,那么就

没有可服务对象,也就没有理由继续下去。

setDaemon(boolean on)方法必须在线程

启动之前调用,当线程正在运行时调用会产

生异常。


30.Java线程池技术及原理


    使用线程池的好处: 

    1.减少在创建和销毁线程上所花的时间以及系统资源的开销 
    2.如不使用线程池,有可能造成系统创建大量线程而导致消耗完系统内存以及”过度切换”。

   JDK自带线程池总类

1)newFixedThreadPool创建一个指定工作线程数量的线程池。每当提交一个任务就创建一个工作线程,如果工作线程数量达到线程池初始的最大数,则将提交的任务存入到池队列中。 

2)newCachedThreadPool创建一个可缓存的线程池。工作线程的创建数量几乎没有限制(其实也有限制的,数目为Interger. MAX_VALUE

3)newSingleThreadExecutor创建一个单线程化的Executor,即只创建唯一的工作者线程来执行任务,如果这个线程异常结束,会有另一个取代它,保证顺序执行(我觉得这点是它的特色)

4)newScheduleThreadPool创建一个定长的线程池,

31.java并发包concurrent及常用的类

http://www.cnblogs.com/vijozsoft/p/558562

0.html//集合

Java内存模型:


java内存模型中规定了所有的变量都存储在主内存中,每条线程还有自己的工作内存(可以与前面将的处理器的高速缓存类比),线程的工作内存中保存了该线程使用到的变量到主内存副本拷贝,线程对变量的所有操作(读取、赋值)都必须在工作内存中进行,而不能直接读写主内存中的变量。不同线程之间无法直接访问对方工作内存中的变量,线程间变量值的传递均需要在主内存来完成,线程、主内存和工作内存的交互关系如下图所示



volatile关键字

  • 可见性。对一个volatile变量的读,总是能看到(任意线程)对这个volatile变量最后的写入。

  • 原子性:对任意单个volatile变量的读/写具有原子性,

下面对volatile写和volatile读的内存语义做个总结:

  • 线程A写一个volatile变量,实质上是线程A向接下来将要读这个volatile变量的某个线程发出了(其对共享变量所在修改的)消息。

  • 线程B读一个volatile变量,实质上是线程B接收了之前某个线程发出的(在写这个volatile变量之前对共享变量所做修改的)消息。

  • 线程A写一个volatile变量,随后线程B读这个volatile变量,这个过程实质上是线程A通过主内存向线程B发送消息。



1) ConcurrentHashMap

 ConcurrentHashMap是线程安全的HashMap的实现,默认构造同样有initialCapacity和loadFactor属性,不过还多了一个concurrencyLevel属性,三属性默认值分别为16、0.75及16。其内部使用锁分段技术,维持这锁Segment的数组,在Segment数组中又存放着Entity[]数组,内部hash算法将数据较均匀分布在不同锁中。

oncurrentHashMap默认情况下采用将数据分为16个段进行存储,并且16个段分别持有各自不同的锁Segment,锁仅用于put和remove等改变集合对象的操作,基于volatile及HashEntry链表的不变性实现了读取的不加锁。这些方式使得ConcurrentHashMap能够保持极好的并发支持,尤其是对于读远比插入和删除频繁的Map而言,而它采用的这些方法也可谓是对于Java内存模型、并发机制深刻掌握的体现。

ConcurrentLinkedQueue是一个基于链接节点的、无界的、线程安全的队列




0 0
原创粉丝点击