`

Java中Thread线程

    博客分类:
  • Java
阅读更多
1. 实现线程的两种方式

1. 继承Thread类并重写run方法

public class ThreadTest{
    public static void main(String[] args){
        Thread1 t1 = new Thread1("first thread");
        Thread2 t2 = new Thread2("second thread");
        System.out.println(t1.getName());
        System.out.println(t2.getName());
        t1.start();
        t2.start();
    }
}
class Thread1 extends Thread{
    public Thread1(String name){
        super(name);
    }
    @Override
    public void run(){
        for(int i = 0; i < 100; i++){
            System.out.println("hello world: " + i);
        }
    }
}
class Thread2 extends Thread{
    public Thread2(String name){
        super(name);
    }
    @Override
    public void run(){
        for(int i = 0; i < 100; i++){
            System.out.println("welcome: " + i);
        }
    }
}


2. 定义实现runnable接口的类进而实现run方法

public class ThreadTest2{
    public static void main(String[] args){
        Thread t1 = new Thread(new MyThread());
        t1.start();
        Thread t2 = new Thread(new MyThread2());
        t2.start();
    }
}
class MyThread implements Runnable{
    @Override
    public void run(){
        for(int i = 0; i < 100; i++){
            System.out.println("hello :" + i);
        }
    }
}
class MyThread2 implements Runnable{
    @Override
    public void run(){
        for(int i = 0; i < 100; i++){
            System.out.println("welcome: " + i);
        }
    }
}


2. 线程

1) Thread类也实现了Runnable接口,因此实现了Runnable接口中的run方法;
2) 当生成一个线程对象时,如果没有为其设定名字,那么线程对象的名字将使用如下形式:Thread-number,该number将是自动增加的,并被所有的Thread对象所共享(因为它是static的成员变量)。
3) 当使用第一种方式来生成线程对象时,我们需要重写run方法,因为Thread类的run方法此时什么事情也不做。
4) 当使用第二种方式来生成线程对象时,我们需要实现Runnable接口的run方法,然后使用newThread(newMyThread())(假如MyThread已经实现了Runnable接口)来生成线程对象,这时的线程对象的run方法就会调用MyThread类的run方法,这样我们自己编写的run方法就执行了。

停止线程要重新构造方法,不能使用stop()方法。

run()方法并非是由刚创建的新线程所执行的,而是被创建新线程的当前线程所执行
start()方法才是被刚创建的新线程所执行的
run方法会等待线程执行完,再执行后面的代码
start方法会不会带线程,就会执行后面的代码

线程控制逃逸规则
某个线程控制的对象是资源本身,线程安全
某个线程控制的对象仅仅是某个资源的引用,线程不安全


3. 线程变量

HelloThread中i定义的位置。
线程的全局变量只有一个,而局部变量每一个都会有一个。
关于成员变量与局部变量:如果一个变量是成员变量,那么多个线程对同一个对象的成员变量进行操作时,他们对该成员变量是彼此影响的(也就是说一个线程对成员变量的改变会影响到另一个线程)。
public class ThreadTest3{
    public static void main(String[] args){
        Runnable r = new HelloThread();
        Thread t1 = new Thread(r);
        //r = new HelloThread();
        Thread t2 = new Thread(r);
        t1.start();
        t2.start();
    }
}
class HelloThread implements Runnable{
    int i;
    @Override
    public void run(){
        int i = 0;
        while(true){
            System.out.println("number: " + this.i++);
            try{
                Thread.sleep((long)(Math.random() * 1000));
            }
            catch (InterruptedException e){
                e.printStackTrace();
            }
            if(50 == this.i){
                break;
            }
        }
    }
}

4. Synchronized关键字

当synchronized关键字修饰一个方法的时候,该方法叫做同步方法。
public class FetchMoney{
    public static void main(String[] args){
        Bank bank = new Bank();
        Thread t1 = new MoneyThread(bank); // 柜台
        //bank = new Bank();
        Thread t2 = new MoneyThread(bank); // 取款机
        t1.start();
        t2.start();
    }
}
class Bank{
    private int money = 1000;
    public synchronized int getMoney(int number){
        if(number < 0){
            return -1;
        }
        else if(number > money){
            return -2;
        }
        else if(money < 0){
            return -3;
        }
        else{
            try{
                Thread.sleep(1000);
            }
            catch (InterruptedException e){
                e.printStackTrace();
            }
            money -= number;
            System.out.println("left money: " + money);
            return number;
        }        
    }
}
class MoneyThread extends Thread{
    private Bank bank;
    public MoneyThread(Bank bank){
        this.bank = bank;
    }
    @Override
    public void run(){
        System.out.println(bank.getMoney(800));
    }
}

Java中的每个对象都有一个锁(lock)或者叫做监视器(monitor),当访问某个对象的synchronized方法时,表示将该对象上锁,此时其他任何线程都无法再去访问该synchronized方法了,直到之前的那个线程执行方法完毕后(或者是抛出了异常),那么将该对象的锁释放掉,其他线程才有可能再去访问该synchronized方法。

如果一个对象有多个synchronized方法,某一时刻某个线程已经进入到了某个synchronized方法,那么在该方法没有执行完毕前,其他线程是无法访问该对象的任何synchronized方法的。
public class ThreadTest4{
    public static void main(String[] args){
        Example example = new Example();
        Thread t1 = new TheThread(example);
        // 区分一个对象还是两个对象
        // example = new Example();
        Thread t2 = new TheThread2(example);
        t1.start();
        t2.start();
    }
}
class Example{
    //static对顺序的影响
    public synchronized void execute(){
        for(int i = 0; i < 20; i++){
            try{
                Thread.sleep((long)(Math.random() * 1000));
            }
            catch (InterruptedException e){
                e.printStackTrace();
            }
            System.out.println("hello: " + i);
        }
    }
    //static对顺序的影响
    public synchronized void execute2(){
        for(int i = 0; i < 20; i++){
            try{
                Thread.sleep((long)(Math.random() * 1000));
            }
            catch (InterruptedException e){
                e.printStackTrace();
            }
            System.out.println("world: " + i);
        }
    }
}
class TheThread extends Thread{
    private Example example;
    public TheThread(Example example){
        this.example = example;
    }
    @Override
    public void run(){
        this.example.execute();
    }
}
class TheThread2 extends Thread{
    private Example example;
    public TheThread2(Example example){
        this.example = example;
    }
    @Override
    public void run(){
        this.example.execute2();
    }
}
1) Static方法是属于类的,不是属于对象的。它对应的对象是class对象。
   一个类有两个synchronized static方法,则先执行一个,后执行另一个。
2) 如果某个synchronized方法是static的,那么当线程访问该方法时,它锁的并不是synchronized方法所在的对象,而是synchronized方法所在的对象所对应的Class对象,因为Java中无论一个类有多少个对象,这些对象会对应唯一一个Class对象,因此当线程分别访问同一个类的两个对象的两个static,synchronized方法时,他们的执行顺序也是顺序的,也就是说一个线程先去执行方法,执行完毕后另一个线程才开始执行。


5. Synchronized块

Synchronized块(比synchronized方法更加细粒度)对object进行上锁(传入的object是否是一个object)。
public class ThreadTest5{
    public static void main(String[] args){
        Example2 e = new Example2();
        TheThread3 t1 = new TheThread3(e);
        e = new Example2();
        TheThread4 t2 = new TheThread4(e);
        t1.start();
        t2.start();
    }
}
class Example2{
    private Object object = new Object();
    public void execute(){
        synchronized (this){
            for (int i = 0; i < 20; i++){
                try{
                    Thread.sleep((long) (Math.random() * 1000));
                }
                catch (InterruptedException e){
                    e.printStackTrace();
                }
                System.out.println("hello: " + i);
            }
        }
    }
    public void execute2(){
        synchronized(this){
            for (int i = 0; i < 20; i++){
                try{
                    Thread.sleep((long) (Math.random() * 1000));
                }
                catch (InterruptedException e){
                    e.printStackTrace();
                }
                System.out.println("world: " + i);
            }
        }
    }
}
class TheThread3 extends Thread{
    private Example2 example;
    public TheThread3(Example2 example){
        this.example = example;
    }
    @Override
    public void run(){
        this.example.execute();
    }
}
class TheThread4 extends Thread{
    private Example2 example;
    public TheThread4(Example2 example){
        this.example = example;
    }
    @Override
    public void run(){
        this.example.execute2();
    }
}
两个对象一定的乱序的。


6. 死锁(deadlock)

wait方法,调用必须在synchronized方法或块当中。
public class Sample{
    private int number;
    public synchronized void increase(){
        while (0 != number){
            try{
                wait();
            }
            catch (InterruptedException e){
                e.printStackTrace();
            }
        }
        number++;
        System.out.println(number);
        notify();
    }
    public synchronized void decrease(){
        while (0 == number){
            try{
                wait();
            }
            catch (InterruptedException e){
                e.printStackTrace();
            }
        }
        number--;
        System.out.println(number);
        notify();
    }
}
public class IncreaseThread extends Thread{
    private Sample sample;
    public IncreaseThread(Sample sample){
        this.sample = sample;
    }
    @Override
    public void run(){
        for(int i = 0; i < 20; i++){
            try{
                Thread.sleep((long)(Math.random() * 1000));
            }
            catch (InterruptedException e){
                e.printStackTrace();
            }
            sample.increase();
        }
    }
}
public class DecreaseThread extends Thread{
private Sample sample;
    public DecreaseThread(Sample sample){
        this.sample = sample;
    }
    @Override
    public void run(){
        for(int i = 0; i < 20; i++){
            try{
                Thread.sleep((long)(Math.random() * 1000));
            }
            catch (InterruptedException e){
                e.printStackTrace();
            }
            sample.decrease();
        }
    }
}
public class MainTest{
    public static void main(String[] args){
        Sample sample = new Sample();
        Thread t1 = new IncreaseThread(sample);
        Thread t2 = new DecreaseThread(sample);
        Thread t3 = new IncreaseThread(sample);
        Thread t4 = new DecreaseThread(sample);
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }
}
4个线程的时候wait之后还需要判断用while不用if。


7. 说明

wait与notify方法都是定义在Object类中,而且是final的,因此会被所有的Java类所继承并且无法重写。这两个方法要求在调用时线程应该已经获得了对象的锁,因此对这两个方法的调用需要放在synchronized方法或块当中。当线程执行了wait方法时,它会释放掉对象的锁。

另一个会导致线程暂停的方法就是Thread类的sleep方法,它会导致线程睡眠指定的毫秒数,但线程在睡眠的过程中是不会释放掉对象的锁的。


8. 单例模式

对于单例模式(Singleton)来说,如果在getInstance()方法中生成Singleton实例则可能会产生同步问题,即可能会生成两个不同的对象。
public class Singleton{
    private static Singleton singleton;
    private Singleton(){}
    public static Singleton getInstance(){
        if (null == singleton){
            try{
                Thread.sleep((long) (Math.random() * 4000));
            }
            catch (InterruptedException e){
                e.printStackTrace();
            }
            singleton = new Singleton();
        }
        return singleton;
    }
    public static void main(String[] args){
        new MyThread().start();
        new MyThread().start();
    }
}
class MyThread extends Thread{
    @Override
    public void run(){
        System.out.println(Singleton.getInstance());
    }
}
运行结果:
code17.Singleton@1fa1bb6
code17.Singleton@1315d34
分享到:
评论

相关推荐

    Java 模拟线程并发

    在Java中,线程并发可以通过多种方式实现,包括继承Thread类、实现Runnable接口以及使用ExecutorService和Future等高级API。下面将详细探讨这些知识点。 首先,Java中创建线程主要有两种方法。一种是通过继承Thread...

    Java多线程机制(讲述java里面与多线程有关的函数)

    Java多线程机制是Java编程中至关重要的一部分,它允许程序同时执行多个任务,提升应用程序的效率和响应性。以下是对各个知识点的详细说明: 9.1 Java中的线程: Java程序中的线程是在操作系统级别的线程基础上进行...

    在Java中创建线程有两种方法

    在Java编程语言中,创建线程是实现并发执行任务的关键步骤。Java提供了两种主要的方法来创建线程,分别是直接继承自`Thread`类和实现`Runnable`接口。这两种方法各有其特点和适用场景。 1. **继承Thread类**: 当...

    Java-Thread-Affinity,将Java线程绑定到给定的内核.zip

    在Java中,通常我们通过Java的`java.lang.Thread`类进行线程的创建和管理,但默认情况下,Java并不提供直接设置线程亲和性的API。Java-Thread-Affinity库填补了这一空白,它允许开发者在Java程序中方便地绑定线程到...

    java多线程进度条

    为了在多线程中同步进度更新,我们可以利用synchronized关键字、wait()、notify()方法,或者使用Java并发库中的高级工具,如Semaphore、CyclicBarrier或CountDownLatch等。 一个简单的进度条实现可以采用共享变量...

    java多线程Demo

    在Java中,实现多线程有两种主要方式:继承Thread类和实现Runnable接口。 1. 继承Thread类: 当我们创建一个新的类,让它继承Thread类时,可以通过重写`run()`方法来定义线程执行的任务。然后创建该类的对象,并...

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

    java线程第二版中英文 java线程第二版中英文 线程并不是新的概念:许多操作系统和语言都支持它们。在Java出现以前,似乎人人都在谈论线程,却很少有人使用它。用线程编程是技巧性很强的且不可移植。 而在Java中却...

    Java Thread多线程全面解析

    Java Thread多线程全面解析涵盖了Java编程中关于线程的重要概念和实践技巧。在Java中,多线程是并发编程的基础,允许程序同时执行多个任务,提高系统资源利用率和应用程序的响应速度。 线程的生命周期包括五个基本...

    Java的线程和Java AppletJava的线程和Java AppletJava的线程和Java Applet

    2. **线程模型**:Java中的线程由虚拟CPU(封装在`java.lang.Thread`类中)、执行的代码(传递给`Thread`类)和处理的数据(传递给`Thread`类)三部分组成。 3. **创建线程**:可以通过继承`Thread`类或实现`...

    java中线程的应用例子

    在Java中,创建线程有两种主要方式:继承`Thread`类或实现`Runnable`接口。这里,我们假设`Thread.java`中定义了一个名为`MyThread`的类,它直接继承自`Thread`: ```java public class MyThread extends Thread { ...

    JAVAJAVA多线程教学演示系统论文

    2. **JAVA多线程API**:论文会详细阐述JAVA提供的多线程API,如Thread类、Runnable接口、ExecutorService和Future接口等。通过实例解析这些类和接口的使用方法,帮助读者理解如何在实际编程中创建和管理线程。 3. *...

    Java多线程知识点总结

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

    java多线程进度条实例

    SwingWorker 提供了在后台线程中执行任务并在事件调度线程中更新UI的能力,确保了界面的响应性。 以下是一个简单的示例,展示了如何创建一个基于控制台的进度条(对于GUI的实现,可以参考SwingWorker或Task的相关...

    java中的线程让步例子.

    此外,Java中的线程优先级(`Thread.setPriority()`)可以影响线程调度,但同样不应过度依赖。优先级高的线程在调度时理论上会得到更多执行机会,但Java的线程调度策略可能会使这种优先级关系变得复杂,尤其是在多...

    java的thread类重写run方法的双线程从1加到100

    首先,`Thread`类是Java中的核心类,它代表了程序中的一个执行线程。当你创建一个新的`Thread`对象并启动它时,Java虚拟机(JVM)会为这个线程分配CPU时间片,从而使得代码可以在不同的线程间交替执行。 要实现...

    JAVA 线程中启动线程

    在Java编程语言中,线程是程序执行的基本单元,它允许程序并发地执行多个任务。在多线程环境中,程序的执行效率和响应性通常会得到显著提升。本篇文章将详细探讨如何在Java中启动线程,以及相关的重要概念和技术。 ...

    java 多线程并发实例

    在Java中,创建线程主要有两种方式:继承Thread类和实现Runnable接口。在提供的实例中,我们可能会看到这两种方式的运用。 1. 继承Thread类:通过创建新的Thread子类并重写其run()方法,然后创建该子类的实例并调用...

    java中的线程休眠例子

    在Java中,线程休眠主要通过`Thread.sleep()`方法实现。 1. **Thread.sleep()方法详解** `Thread.sleep(long millis)`方法用于使当前正在执行的线程暂停执行,参数`millis`代表线程将睡眠的毫秒数。如果参数是0,...

Global site tag (gtag.js) - Google Analytics