java多线程

本文详细介绍了Java中线程的基本概念及实现方式,包括创建线程的两种方法、线程同步机制、线程的状态管理等核心内容,并提供了丰富的示例代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

                            ----------- android培训java培训、java学习型技术博客、期待与您交流! ------------




1: 创建线程方式一

  继承Thread类

1.子类覆盖父类中的run方法,将线程运行 的代码存放在run中。

2.建立子类对象的同时线程也被创建。

3.通过调用start方法开启线程。

 例程

         

2:创建线程方式二

实现Runnable接口

1.子类覆盖接口中的run方法。

2.通过Thread类创建线程,并将实现了 Runnable接口的子类对象作为参数传递给 Thread类的构造函数。

3.Thread类对象调用start方法开启线程


3: 同步

格式:

synchronized(对象)

{

需要同步的代码;

}

同步可以解决安全问题的根本原因就在那个对象上。

该对象如同锁的功能。

         

       同步的前提:

同步需要两个或者两个以上的线程。

多个线程使用的是同一个锁。

       未满足这两个条件,不能称其为同步。

       同步的弊端:

                       当线程相当多时,因为每个线程都会去判断 同步上的锁,这是很耗费资源的,无形 中会降低程序的运行效率。

                   

4: 停止线程

 1.定义循环结束标记

因为线程运行代码一般都是循环,只要控制了循环即 可。


例子:stopped  为控制线程的结束标记

<span style="color:#330033"> private class CounterThread implements Runnable {
        
        private int count = 0;
        private boolean stopped = true;
        
        public void setStopped(boolean stopped) {
            this.stopped = stopped;
        }
        
        //用一个变量在控制
        public void run() {
            while (stopped) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                lbljava.setText("《Java编程词典》第" + (count++) + "次更新!");
            }
        }</span>
<span style="color:#330033">protected void do_button2_actionPerformed(ActionEvent e) {
        if (counter == null) {          
            return;
        }
        counter.setStopped(false);
    }</span>



2.使用interrupt(中断)方法。

该方法是结束线程的冻结状态,使线程回到 运行状态中来。


注:stop方法已经过时不再使用。


5:  线程类方法

             currentThread() 

         返回对当前正在执行的线程对象的引用(实现接口方式时使用)


sleep(long millis) 

          在指定的毫秒数内让当前正在执行的线程休眠(暂停执行)。

本线程不会去抢,除非sleep结束。

多个线程之间都会去抢执行权限,不会考虑优先级。


yield() 

          暂停当前正在执行的线程对象,并执行其他线程。

          只给本类或者优先级大于本类优先级的线程去抢。


          join() 

          等待该线程终止。

          放在start()前面则没有用处。


          setDaemon(boolean on) 

          将该线程标记为守护线程,守护线程需要依赖其他线程,会在虚拟机停止的时候停止。         


    setPriority(int num)

    自定义线程名称

    toString()


6: 线程的四种状态      


       还有一种状态比较特殊: 就绪。具备了执行资格,但是还没有获得资源。


7: 进程和线程      

进程:同一个操作系统中执行的一个子程序,包含了三部分虚拟CPU、代码、数据

多进程:同一个操作系统中执行的多个并行的子程序。可以提高cpu的使用率

线程:在同一个进程当中执行的子程序流

多线程:同一个进程当中并发执行的多个子程序流。可以提高cpu的使用率

进程与线程的区别:

进程有独立的进程空间,进程中的数据存放空间(堆空间和栈空间)是独立的。

线程的堆空间是共享的,栈空间是独立的,线程消耗的资源也比进程小,相互之间可以影响的。


8: 查看线程的运行状态

<span style="color:#330033">package com.ylctest.thread;

public class ThreadState implements Runnable {
    public synchronized void waitForASecond() throws InterruptedException {
        wait(500); // 使当前线程等待0.5秒或其他线程调用notify()或notifyAll()方法
    }
    
    public synchronized void waitForYears() throws InterruptedException {
        wait(); // 使当前线程永久等待,直到其他线程调用notify()或notifyAll()方法
    }
    
    public synchronized void notifyNow() throws InterruptedException {
        notify(); // 唤醒由调用wait()方法进入等待状态的线程
    }
    
    public void run() {
        try {
            waitForASecond(); // 在新线程中运行waitForASecond()方法
            waitForYears(); // 在新线程中运行waitForYears()方法
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}</span>

<span style="color:#330033">package com.mingrisoft.thread;

public class Test {
    public static void main(String[] args) throws InterruptedException {
        ThreadState state = new ThreadState();// 创建State对象
        Thread thread = new Thread(state);// 利用State对象创建Thread对象
        System.out.println("新建线程:" + thread.getState());// 输出线程状态


        thread.start(); // 调用thread对象的start()方法,启动新线程
        System.out.println("启动线程:" + thread.getState());// 输出线程状态


        Thread.sleep(100); // 当前线程休眠0.1秒,使新线程运行waitForASecond()方法
        System.out.println("计时等待:" + thread.getState());// 输出线程状态


        Thread.sleep(1000); // 当前线程休眠1秒,使新线程运行waitForYears()方法
        System.out.println("等待线程:" + thread.getState());// 输出线程状态


        state.notifyNow(); // 调用state的notifyNow()方法
        System.out.println("唤醒线程:" + thread.getState());// 输出线程状态


        Thread.sleep(1000); // 当前线程休眠1秒,使新线程结束
        System.out.println("终止线程:" + thread.getState());// 输出线程状态
    }
    
}
</span>


9. 守护线程

              是为用户线程提供服务的,垃圾回收线程就是一个守护线程。

用户线程和守护两者几乎没有区别,唯一的不同之处就在于虚拟机的离开:如果用户已经全部退出运行了,只剩下守护存在了,虚拟机也就退出了。 因为没有了被守护者,守护线程也就没有工作可做了,也就没有继续运行程序的必要了。 


             例子:

   

<span style="color:#330033">//守护线程如下:



package com.ylctest.thread;

public class Timer implements Runnable {
    public void run() {
        long currentTime = System.currentTimeMillis();// 获得系统当前时间
        long processTime = 0;// 设置系统运行时间为0
        while (true) {// 如果系统运行时间发生变化就输出
            if ((System.currentTimeMillis() - currentTime) > processTime) {
                processTime = System.currentTimeMillis() - currentTime;
                System.out.println("程序运行时间:" + processTime);
            }
        }
    }
}</span>
<span style="color:#330033">//用户线程如下



package com.ylctest.thread;

public class Worker implements Runnable {
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println("通过" + i + "辆汽车!");
        }
    }
}</span>
<span style="color:#330033">package com.ylctest.thread;

public class DaemonThreadTest {
    public static void main(String[] args) {
        Thread userThread = new Thread(new Worker()); // 创建用户线程
        Thread daemonThread = new Thread(new Timer()); // 创建守护线程
        daemonThread.setDaemon(true); // 设置守护线程
        userThread.start(); // 启动用户线程
        daemonThread.start(); // 启动守护线程
    }
}
</span>


10: 线程的插队运行 --join 方法

         当让一个线程优先于其他线程运行时此时除了可以设置该线程的优先级高于其他的线程外,还可以

       使用Thread 方法的join() 方法。

            

         例子:

   

<span style="color:#330033">package com.ylctest.thread;

public class EmergencyThread implements Runnable {
    
    @Override
    public void run() {
        for (int i = 1; i < 6; i++) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("紧急情况:" + i + "号车出发!");
        }
    }
}</span>
<span style="color:#330033">public class JoinThread {
    
    public static void main(String[] args) {
        Thread thread = new Thread(new EmergencyThread());
        thread.start();         
        
        
        for (int i = 1; i < 6; i++) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("正常情况:" + i + "号车出发!");
            try {
                thread.join();     //此时紧急情况优先于正常情况运行。
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}</span>



11:  最简单也是最常用的: 使用方法实现线程同步

       所谓同步方法,即有Syschronized 关键字修饰的方法。其原理是通过java的内置锁实现的,其实每个
       java 对象都有一个内置锁,如果方法用此关键字声明了,该内置锁会保护整个方法。

       例子如下:

       这是一个银行类: 负责往里头存钱 ,和 查询当前存款。
  1. private class Bank {
  2.         private int account = 100;// 每个账户的初始金额是100元
  3.         
  4.         public synchronized void deposit(int money) {// 向账户中存入money元
  5.             account += money;
  6.         }
  7.         
  8.         public int getAccount() {// 查询账户余额
  9.             return account;
  10.         }
  11.     }

这是个继承Runnable 的Trannsfer类: 这是一个带传入参数的
  1.   private class Transfer implements Runnable {
  2.         private Bank bank;
  3.         private JTextArea textArea;
  4.         
  5.         public Transfer(Bank bank, JTextArea textArea) {// 初始化变量
  6.             this.bank = bank;
  7.             this.textArea = textArea;
  8.         }
  9.         
  10.         public void run() {
  11.             for (int i = 0; i < 10; i++)

这是线程的运行如下:
  1. Bank bank = new Bank();
  2.         Thread thread1 = new Thread(new Transfer(bank, thread1TextArea));
  3.         thread1.start();
  4.         Thread thread2 = new Thread(new Transfer(bank, thread2TextArea));
  5.         thread2.start()

打印结果如下:

一线程:   
账户的余额是:110   
账户的余额是:130
账户的余额是:160
账户的余额是:180
账户的余额是:200
账户的余额是:210
账户的余额是:230
账户的余额是:260
账户的余额是:280
账户的余额是:300


二线程:
账户的余额是:120
账户的余额是:140
账户的余额是:150
账户的余额是:170
账户的余额是:190
账户的余额是:220
账户的余额是:240
账户的余额是:260
账户的余额是:270
账户的余额是:290




12: 使用代码块实现线程的同步:
    Syschonized 不仅可以修饰方法,还可以修饰代码块。
     格式为:  syschronized(objcect)  {}

     还是刚才的例子:修改如下:
  1.   private class Bank {
  2.         private int account = 100;
  3.         
  4.         public void deposit(int money) {
  5.             synchronized (this) {// 获得Bank类的锁 *******注意了
  6.                 account += money;
  7.             }
  8.         }
  9.         
  10.         public int getAccount() {
  11.             return account;
  12.         }
  13.     }

13: 使用特殊变量实现线程同步:
       volatile 关键字为域变量提供了一种免锁机制。使用这个关键字相当于告诉虚拟机该变量可能会被其他线程修改,因此每次使用该变量时就要
       更新计算,而不是使用寄存器里头的值。它不能用来修饰final 类型的变量。

        还是刚才的例子:
  1. private class Bank {
  2.         private volatile int account = 100;// 将域变量用volatile修饰 *******注意了
  3.         
  4.         public void deposit(int money) {// 向账户中存钱
  5.             account += money;
  6.         }
  7.         
  8.         public int getAccount() {// 获得账户余额
  9.             return account;
  10.         }
  11.     }

14: 使用重入锁实现线程的同步:

       java se 5.0 增加了一个java.util.comcurrent  包来支持同步。
       ReentrantLock类是可重入  互斥  实现了Lock接口的锁。

        方法有:
                   ReentrantLock()   无参构造函数,创建一个实例
                   lock()     获得锁
                   unlock()   释放锁。

<span style="color:#330033">   private class Bank {
        private int account = 100;// 账户的初始金额是100
        private Lock lock = new ReentrantLock();// 创建重入锁对象  **********注意了
        
        public void deposit(int money) {
            lock.lock();// 打开锁
            try {
                account += money;
            } finally {
                lock.unlock();// 关闭锁
            }
        }
        
        public int getAccount() {// 查看余额
            return account;
        }
    }</span>


15: 使用线程局部变量实现线程同步:


        类: ThreadLocal   来管理变量,则每个使用该变量的线程都会获得该变量的副本,副本之间相互独立,这样每个线程都
        可以随意修改自己的副本,而不会对其他线程产生影响。
   
         方法如下:
                ThreadLocal  () 无参构造函数
                get() 返回当前线程副本中的值
                initialValue() 返回当前线程的初始值。
                set(T value) 设置副本中的值。




           应用如下:
            
          发现account变量用new ThreadLocal<Integer>() 来创建了

<span style="color:#330033">public class Bank {
    // 使用ThreadLocal类来管理共享变量account
    private static ThreadLocal<Integer> account = new ThreadLocal<Integer>() {  //*******注意
        @Override
        protected Integer initialValue() {
            return 100;// 重写initialValue()方法,将account的初始值设为100
        }
    };
    
    public void deposit(int money) {
        account.set(account.get() + money);// 利用account的get()、set()方法实现存钱 //*******注意
    }
    
    public int getAccount() {// 获得账户余额
        return account.get(); //*******注意
    }
}</span>


          ----------------------- android培训java培训、java学习型技术博客、期待与您交流! ----------------------

         详情请查看:http://edu.youkuaiyun.com/heima


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值