java多线程

多线程是多任务的一种特别的形式,但多线程使用了更小的资源开销;;多线程能满足程序员编写高效率的程序来达到充分利用 CPU 的目的。

新建状态:使用 new 关键字和 Thread 类或其子类建立一个线程对象后,该线程对象就处于新建状态。它保持这个状态直到程序 start() 这个线程。

就绪状态:当线程对象调用了start()方法之后,该线程就进入就绪状态。就绪状态的线程处于就绪队列中,要等待JVM里线程调度器的调度。

运行状态:如果就绪状态的线程获取 CPU 资源,就可以执行 run(),此时线程便处于运行状态。处于运行状态的线程最为复杂,它可以变为阻塞状态、就绪状态和死亡状态。

阻塞状态:如果一个线程执行了sleep(睡眠)、suspend(挂起)等方法,失去所占用资源之后,该线程就从运行状态进入阻塞状态。在睡眠时间已到或获得设备资源后可以重新进入就绪状态。可以分为三种:

    ·等待阻塞:运行状态中的线程执行 wait() 方法,使线程进入到等待阻塞状态

    ·同步阻塞:线程在获取 synchronized 同步锁失败(因为同步锁被其他线程占用)。

    ·其他阻塞:通过调用线程的 sleep() 或 join() 发出了 I/O 请求时,线程就会进入到阻塞状态。当sleep() 状态超时,join() 等待线程终止或超时,或者 I/O 处理完毕,线程重新转入就绪状态。

死亡状态:一个运行状态的线程完成任务或者其他终止条件发生时,该线程就切换到终止状态。

 

Java 提供了三种创建线程的方法:

通过实现 Runnable 接口;

通过继承 Thread 类本身;

通过 Callable 和 Future 创建线程。

 

创建线程的三种方式的对比

1. 采用实现 Runnable、Callable 接口的方式创建多线程时,线程类只是实现了 Runnable 接口或 Callable 接口,还可以继承其他类。

2. 使用继承 Thread 类的方式创建多线程时,编写简单,如果需要访问当前线程,则无需使用 Thread.currentThread() 方法,直接使用 this 即可获得当前线程。

 

多线程有几种实现方法?同步有几种实现方法?

多线程有两种实现方法,分别是继承 Thread 类与实现 Runnable 接口

同步的实现方面有两种,分别是 synchronized,wait 与 notify

wait():使一个线程处于等待状态,并且释放所持有的对象的 lock。

sleep(): 使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要捕捉

InterruptedException 异常。

notify():唤醒一个处于等待状态的线程,注意的是在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由 JVM 确定唤醒哪个线程,而且不是按优先级。

Allnotity():唤醒所有处入等待状态的线程,注意并不是给所有唤醒线程一个对象的锁,而是让它们竞争。

wait和sleep区别

对于sleep()方法,我们首先要知道该方法是属于Thread类中的。而wait()方法,则是属于Object类中的。

sleep()方法导致了程序暂停执行指定的时间,让出cpu该其他线程,但是他的监控状态依然保持者,当指定的时间到了又会自动恢复运行状态。

在调用sleep()方法的过程中,线程不会释放对象锁。

而当调用wait()方法的时候,线程会放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象调用notify()方法后本线程才进入对象锁定池准备

获取对象锁进入运行状态。

 

.启动一个线程是用 run()还是 start()? .

启动一个线程是调用 start()方法,使线程就绪状态,以后可以被调度为运行状态,一个线程必须关联一些具体的执行代码,run()方法是该线程所关联的执行代码。

 

当一个线程进入一个对象的一个 synchronized 方法后,其它线程是否可进入此对象其它方法?

分几种情况:

1.其他方法前是否加了 synchronized 关键字,如果没加,则能。

2.如果这个方法内部调用了 wait,则可以进入其他 synchronized 方法。

3.如果其他个方法都加了 synchronized 关键字,并且内部没有调用 wait,则不能。

4.如果其他方法是 static,它用的同步锁是当前类的字节码,与非静态的方法不能同步,因为非静态的方法用的是 this。

线程:

Thread类中有许多管理线程的方法,包括创建、启动、暂停他们,所有操作都是从run()操作开始的,并且在run()方法内编写需要在独立线程内执行的代码。执行的线程都是通过调用run()开始的。

 

没有参数的run()方法是自动被调用的,而带参数的run()是被重载的,必须显式的调用。

两种方法:

///这种方式把线程相关的代码和线程要执行的代码分离开来

class ThreadTest implements Runnable{

public void run(){

System.out.println("run here;");

}

public static void main(String[] args){

ThreadTest tt=new ThreadTest();

Thread t1=new Thread(tt);

Thread t2=new Thread(tt);

t1.start();t2.start();

}

}

///另一种方式就是参数式匿名内部类

class ThreadTest {

public static void main(String[] args){

Thread tt=new Thread(new Runnable(){

public void run(){

System.out.println("thread;;;");

}

}  );

tt.start();

}

}

 

 

在调用start()方法前线程还不是活的,即调用isAlive()方法的结果为false

如果已经启动,且还没有完成run()方法,则为true;

 

Thread类实现了Runnable接口,不是抽象类。;;run()是由线程执行的方法;;

 

线程同步:

1:共享变量:使用同步使得一个线程正确转到另一个线程

2:存在于同一个内存空间中的所有线程:同一进程中的线程可以共享相同的进程上下文,包括内存空间。只要访问共享变量,线程就可以方便的互相交换数据。但是必须受控访问共享变量

3:受控访问的同步:为实现受控方式访问数据,java中两个关键字:synchronized和volatile

Synchronized:一次只有一个线程可以执行代码受保护的部分;一个线程更改的数据对于其他线程是可见的。

4:确保共享数据更改的可见性:同步可以让用户确保线程看到一致的内存视图;

Volatile比同步更简单,只适合于控制对基本变量的单个实例的访问。当一个变量被声明成volatile,任何对该变量的写操作都会绕过高速缓存,直接写入主内存,读取也是直接读取主内存。这样所有线程在任何时候看到的volatile变量值都是相同的。

5:用锁保护的原子代码块:对每个java对象都由一个相关的锁的概念,同一时间只能有一个线程持有java锁,当线程进入synchronized代码块时,线程会阻塞并等待,直到锁可用。当线程处于就绪状态时,并且获得锁后,将执行代码块,当控制退出受保护的代码块,即到达了代码块末尾或者抛出了没有在synchronized块中捕获的异常,它就会释放该锁。

 

同步示例:

public class syncExample{

private static lockobject=new Object();

private static class Thread1 extends Thread{

public void run(){

synchronized(lockobject){

x=y=0;

System.out.println(x);

}

}

}

private static class Thread2 extends Thread{

public void run(){

synchronized(lockobject){

x=y=1;

System.out.println(y);

}

}

}

public static void main(String[] args) {

new Thread1().run();

new Thread2().run();

}

}

在这两个线程中都必须使用同步,使得程序正确执行;

将会打印10或01;如果没有同步还会打印11或00;;

 

他们两个线程都是锁同个对象

synchronized(lockobject){

 

 

public class Main extends Thread{

static Object lock1=new Object();

static Object lock2=new Object();

static volatile int i1,i2,j1,j2,k1,k2;

public void run() {

while(true) {

doit();

check();

}

}

void doit() {

synchronized (lock1) {

i1++;

}

j1++;

synchronized (lock2) {

k1++;k2++;

}

j2++;

synchronized (lock1) {

i2++;

}

}

void check() {

if(i1!=i2) {

System.out.println("i");

}

if(j1!=j2) {

System.out.println("j");

}

if(k1!=k2) {

System.out.println("k");

}

}

    public static void main(String[] args) {

     new Main().start();

     new Main().start();

    }

}

因为check不依靠任何锁,可以在任何时候执行。而且doit没有原子性,所以check可以在doit中间执行;;所以不能确定会输出哪个i,k,j

 

 

更多请看:http://www.runoob.com/java/java-multithreading.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值