创建线程和synchronized关键字

很长时间没有更新博客,恰好这段时间工作上需要使用线程,就稍微花点时间再次复习(学习)了一下线程知识。在此文中我将围绕以下几点对线程进行讲解:

1.线程的创建(thread,runnable)

2.Synchronized关键字(生产者消费者)

一、线程创建

相信学习过java的同学都知道,创建线程无非是两种方式:

(1)继承Thread类;

(2)实现Runnable接口;

那这两种方式都有什么区别呢?就实现方式来看还是有差别的,继承Thread类就需要去重写Thread父类中的run方法,run方法就是执行的公共代码块;而实现Runnable则是对接口中run方法的具体实现,两种方式的run方法的作用相同。下面一起分析一下代码:

package com.cct.thread;
class MyThread extends Thread{  

    private int ticket = 10;
    public void run(){
        for(int i =0;i<500;i++){
            if(this.ticket>0){
                System.out.println(Thread.currentThread().getName()+"在卖票---->"+(this.ticket--));
            }
        }
    }
}

(1)测试一
public static void main(String[] args) {
		MyThread mt1 = new MyThread();
		MyThread mt2 = new MyThread();
		MyThread mt3 = new MyThread();    //创建了三个对象
		mt1.start();
		mt2.start();
		mt3.start();
	}

(2)测试二
public static void main(String[] args) {
		MyThread thr=new MyThread();
		Thread a=new Thread(thr,"1号");
		Thread b=new Thread(thr,"2号");
		Thread c=new Thread(thr,"3号");   //一个对象用三个线程调用
		a.start();
		b.start();
		c.start();
	}

同学们应该可以猜到看出上面的两种测试方式的结果差别,第一个main会给三个线程都分配10张票进行售卖,而第二种则是共用10张票进行售卖,在网上看到很多人描述继承Thread和实现Runnable接口的差别是是否共同消耗同一份资源,我觉得这种说法是错误的,不管是哪种方式实现线程都是可以实现,这点要注意。他们的差别在于除了在类上写的方式有点不一样之外,我觉着比较大的差别是, java只支持但继承,但是可以多实现,所以我认为实现runnable比继承Thread扩展性更强。

二、synchronized关键字

       这是使用线程最常用的关键字之一,它的作用是在同一时间点只有一个线程获得锁并进入执行代码,其他线程如也需要获得这把锁,则须要在外等待,直到这个线程执行完。

一、当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。

二、然而,当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。

三、尤其关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。

四、第三个例子同样适用其它同步代码块。也就是说,当一个线程访问object的一个synchronized(this)同步代码块时,它就获得了这个object的对象锁。结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。

五、以上规则对其它对象锁同样适用.

话不多说,先来代码进行举例:

一、当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。

public class Thread1 implements Runnable {  
     public void run() {  
          synchronized(this) {  
               for (int i = 0; i < 5; i++) {  
                    System.out.println(Thread.currentThread().getName() + " synchronized loop " + i);  
               }  
          }  
     }  
     public static void main(String[] args) {  
          Thread1 t1 = new Thread1();  
          Thread ta = new Thread(t1, "A");  
          Thread tb = new Thread(t1, "B");  
          ta.start();  
          tb.start();  
     } 
}

结果:  
     A synchronized loop 0  
     A synchronized loop 1  
     A synchronized loop 2  
     A synchronized loop 3  
     A synchronized loop 4  
     B synchronized loop 0  
     B synchronized loop 1  
     B synchronized loop 2  
     B synchronized loop 3  
     B synchronized loop 4

二、然而,当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。

public class Thread2 {  
     public void m4t1() {  
          synchronized(this) {  
               int i = 5;  
               while( i-- > 0) {  
                    System.out.println(Thread.currentThread().getName() + " : " + i);  
                    try {  
                         Thread.sleep(500);  
                    } catch (InterruptedException ie) {  
                    }  
               }  
          }  
     }  
     public void m4t2() {  
          int i = 5;  
          while( i-- > 0) {  
               System.out.println(Thread.currentThread().getName() + " : " + i);  
               try {  
                    Thread.sleep(500);  
               } catch (InterruptedException ie) {  
               }  
          }  
     }  
     public static void main(String[] args) {  
          final Thread2 myt2 = new Thread2();  
          Thread t1 = new Thread(  new Runnable() {  public void run() {  myt2.m4t1();  }  }, "t1"  );  
          Thread t2 = new Thread(  new Runnable() {  public void run() { myt2.m4t2();   }  }, "t2"  );  
          t1.start();  
          t2.start();  
     } 
}

结果:  
     t1 : 4  
     t2 : 4  
     t1 : 3  
     t2 : 3  
     t1 : 2  
     t2 : 2  
     t1 : 1  
     t2 : 1  
     t1 : 0  
     t2 : 0

   三、尤其关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。

    //修改Thread2.m4t2()方法:
     public void m4t2() {
          synchronized(this) {
               int i = 5;
               while( i-- > 0) {
                    System.out.println(Thread.currentThread().getName() + " : " + i);
                    try {
                         Thread.sleep(500);
                    } catch (InterruptedException ie) {
                    }
               }
          }

     }

结果:

     t1 : 4
     t1 : 3
     t1 : 2
     t1 : 1
     t1 : 0
     t2 : 4
     t2 : 3
     t2 : 2
     t2 : 1
     t2 : 0

四、第三个例子同样适用其它同步代码块。也就是说,当一个线程访问object的一个synchronized(this)同步代码块时,它就获得了这个object的对象锁。结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。

  //修改Thread2.m4t2()方法如下:

     public synchronized void m4t2() {
          int i = 5;
          while( i-- > 0) {
               System.out.println(Thread.currentThread().getName() + " : " + i);
               try {
                    Thread.sleep(500);
               } catch (InterruptedException ie) {
               }
          }
     }

结果:
     t1 : 4
     t1 : 3
     t1 : 2
     t1 : 1
     t1 : 0
     t2 : 4
     t2 : 3
     t2 : 2
     t2 : 1
     t2 : 0

  五、以上规则对其它对象锁同样适用:

public class Thread3 {
     class Inner {
          private void m4t1() {
               int i = 5;
               while(i-- > 0) {
                    System.out.println(Thread.currentThread().getName() + " : Inner.m4t1()=" + i);
                    try {
                         Thread.sleep(500);
                    } catch(InterruptedException ie) {
                    }
               }
          }
          private void m4t2() {
               int i = 5;
               while(i-- > 0) {
                    System.out.println(Thread.currentThread().getName() + " : Inner.m4t2()=" + i);
                    try {
                         Thread.sleep(500);
                    } catch(InterruptedException ie) {
                    }
               }
          }
     }
     private void m4t1(Inner inner) {
          synchronized(inner) { //使用对象锁
          inner.m4t1();
     }
     private void m4t2(Inner inner) {
          inner.m4t2();
     }
     public static void main(String[] args) {
          final Thread3 myt3 = new Thread3();
          final Inner inner = myt3.new Inner();
          Thread t1 = new Thread( new Runnable() {public void run() { myt3.m4t1(inner);} }, "t1");
     Thread t2 = new Thread( new Runnable() {public void run() { myt3.m4t2(inner);} }, "t2");
     t1.start();
     t2.start();
  }
}

关键字synchronizedde的锁都是对象锁,而不是扒一段代码(方法)当做锁,所以示例代码中哪个线程先执行带有synchronized关键字的方法,那个线程就执有该方法所述对象的锁,不同对象获得的就是不同对象的锁,它们之间互不影响,有一种情况是相同的,那就是在静态方法上加synchronized关键字,表示锁定class类,类级别的锁,可以叫类锁,在使用的时候注意区分。

synchronized部分借鉴:http://www.wgblogs.com/    在此表示感谢

时间: 2024-10-07 10:45:25

创建线程和synchronized关键字的相关文章

java线程总结--synchronized关键字,原理以及相关的锁

在多线程编程中,synchronized关键字非常常见,当我们需要进行"同步"操作时,我们很多时候需要该该关键字对代码块或者方法进行锁定.被synchronized锁定的代码块,只能同时有一条线程访问该代码块. 上面是很多人的认识,当然也是我之前对synchronized关键字的浅显认识,其实上面的观点存在一定的偏差.在参考了很多文章以及自己动手测试过相关代码后,我觉得有必要记录下自己对synchronized关键字的一些理解,在这个过程,会简单说说synchronized关键字的具体

java基础回顾(五)线程详解以及synchronized关键字

本文将从线程的使用方式.源码.synchronized关键字的使用方式和陷阱以及一些例子展开java线程和synchronized关键字的内容. 一.线程的概念 线程就是程序中单独顺序的流控制.线程本 身不能运行,它只能用于程序中. 二.线程的实现 线程的实现有两种方式: 1.继承Thread类并重写run方法 2.通过定义实现Runnable接口的类进而实现run方法 当用第一种方式时我们需要重写run方法因为Thread类里的run方法什么也不做(见下边的源码),当用第二种方式时我们需要实现

关于Java中的synchronized关键字

[内容简介] 本文主要介绍Java中如何正确的使用synchronized关键字实现线程的互斥锁. [能力需求] 至少已经完整的掌握了Java的语法基础,基本的面向对象知识,及创建并启动线程. [正文] 关于synchronized关键字的使用,很多说法是“锁同一个对象”就可以确保锁是正常的,今天,有人提了一个问题,我觉得非常不错,所以与各位一起分享一下. 在这里,就不提关于线程和synchronized关键字的基本使用了,以非常传统的“银行取钱”的故事为案例,直接上代码:Ps:以下代码是直接敲

java的线程同步机制synchronized关键字的理解

线程同步:               由于同一进程的多个线程共享同一片存储空间,在带来方便的同时,也带来了访问冲突这个严重的问题.Java语言提供了专门机制以解决这种冲突,有效避免了同一个数据对象被多个线程同时访问. 需要明确的几个问题: 1)synchronized关键字可以作为函数的修饰符,也可作为函数内的语句,也就是平时说的同步方法和同步语句块.如果 再细的分类,synchronized可作用于instance变量.object reference(对象引用).static函数和clas

JAVA并发编程3_线程同步之synchronized关键字

在上一篇博客里讲解了JAVA的线程的内存模型,见:JAVA并发编程2_线程安全&内存模型,接着上一篇提到的问题解决多线程共享资源的情况下的线程安全问题. 不安全线程分析 public class Test implements Runnable { private int i = 0; private int getNext() { return i++; } @Override public void run() { // synchronized while (true) { synchro

JAVA线程安全之synchronized关键字的正确用法

JAVA线程安全关于synchronized关键字的用法,今天才知道原来我一直错了.以为用了synchronized关键字包住了代码就可以线程同步安全了. 测试了下.发现是完全的错了.synchronized必须正确的使用才是真正的线程安全...虽然知道这种写法,一直以为却由于懒而用了错误的方法. 看来基础还没有打好.仍需复习加强!工作中犯这种错误是不可原谅的,要知道使用synchronized关键字的地方都是数据敏感的!汗一把... 先贴代码: [java] view plaincopypri

Java多线程:线程同步与关键字synchronized

一.同步的特性1. 不必同步类中所有的方法, 类可以同时拥有同步和非同步方法.2. 如果线程拥有同步和非同步方法, 则非同步方法可以被多个线程自由访问而不受锁的限制. 参见实验1:http://blog.csdn.net/huang_xw/article/details/73185613. 如果两个线程要执行一个类中的同步方法, 并且两个线程使用相同的实例来调用方法, 那么一次只能有一个线程能够执行方法, 另一个需要等待, 直到锁被释放. 参见实验2:http://blog.csdn.net/h

JAVA之旅(十三)——线程的安全性,synchronized关键字,多线程同步代码块,同步函数,同步函数的锁是this

JAVA之旅(十三)--线程的安全性,synchronized关键字,多线程同步代码块,同步函数,同步函数的锁是this 我们继续上个篇幅接着讲线程的知识点 一.线程的安全性 当我们开启四个窗口(线程)把票陆陆续续的卖完了之后,我们要反思一下,这里面有没有安全隐患呢?在实际情况中,这种事情我们是必须要去考虑安全问题的,那我们模拟一下错误 package com.lgl.hellojava; import javax.security.auth.callback.TextInputCallback

Java基础之线程synchronized关键字

synchronized 关键字,它包括两种用法:synchronized 方法和 synchronized 块 1. synchronized 方法:通过在方法声明中加入 synchronized关键字来声明 synchronized 方法.如:  public synchronized void accessVal(int newVal);  synchronized 方法控制对类成员变量的访问:每个类实例对应一把锁,每个 synchronized 方法都必须获得调用该方法的类实例的锁方能执