Java线程初探

首先复习一下什么是线程和进程。应用程序被加载到内存中并准备运行时,我们就说创建了一个进程。进程是一个具有独立功能的程序关于某个数据集合上一次运行活动,进程是系统进行资源分配和调度的一个独立单位。
而线程是进程的一个实体,是CPU调度和分派的基本单位,是进程更小的能独立运行的基本单位。线程没有自己的系统资源,一个进程的多个线程共享操作系统分配各进程的资源。
一个线程和一创建和撤销另外一个线程,同一个进程中的多个线程之间可以并发的执行。一个可运行的程序至少有一个进程,一个进程至少有一个线程。从逻辑角度上来讲,多线程的意义在于一个应用程序中的多个执行部分可以同时执行。但系统并没有将多个线程看成独立的应用从而给其分配资源,系统资源分配和调度的基本单位还是线程。这就是进程和线程的重要区别。

线程状态
在操作系统中,线程通常有四种状态:wait、blocked、running和dead。OS是以队列的形式维护线程的,新建立的线程会被添加到队列的末端,然后从队列头部获取线程,线程的CPU时间片结束后,该线程被归还到队列的队尾。

守护线程和非守护线程
Java中有两种类型的线程:1、守护线程;2、非守护(用户)线程。他们的区别是,父线程创建的守护线程在父线程结束时,守护线程会自动结束;而父线程创建的非守护线程在父线程结束的时候还会继续存活。而对于进程来说,只要有线程还活着,那么这个进程也还活着。
每一个Java应用程序至少都会有一个非守护线程,即主线程。用户关闭了应用程序时,主线程会死亡。但如果程序创建了其他的非守护线程,主进程会继续存活。

创建线程
在Java程序中要创建线程,可通过以下方式来实现:1、implements Runnable接口;2、extends Thread类;3、通过ThreadGroup类实现。

class ThreadA implements Runnable{
    ......
    @Override
    public void run(){
        .....
    }
}

class ThreadB extends Thread{
    .......
    @Override
    public void run(){
        ....
    }
}

public class ThreadSample{
    public static void main(String[] args){
        Thread sampleA = new Thread(new ThreadA());
        sampleA.start();
        Thread sampleB = new ThreadB();
        sampleB.start();
    }
}

以上是最常用的两种创建线程的方式,在run()方法中就可以编写希望线程完成的事务。实现Runnable接口优于通过继承Thread类方法。
此时我们只创建了一个线程,并不是多线程。

线程的基本操作

  • 设置deamon/non-deamon属性
  • 启动/停止线程
  • 挂起/恢复线程   (通过调用stop方法,线程可能会停止;调用supend方法可能挂起线程;通过调用resume方法,另一个运行的程序可以恢复被挂起的线程。但这些方法在J2SE开始就被抛弃了,因为很容易就造成死锁。)
  • 让步操作
  • yield方法
  • 等待其他对象(针对其他运行的线程调用obj.wait()方法,线程可能在等待某个对象的通知。obj只想当前线程想要的等待的对象。)
  • 中断/打扰线程(三个方法:interrupt、isInterrupted和interrupted.)

线程同步
以上只是创建线程和线程的一些基础知识,并不涉及多线程。假如有两筐求,两个非常无聊人做着相反的事情,一个将球从左边一堆移到右面,而另一个相反。正常情况下,这两个人玩够之后两框球的总数应该是不变的。用一个线程模拟一个人,程序如下:

public class BucketBallGame{
    private int bucket[] = {10000, 10000};
    private static boolean RIGHT_TO_LEFT;

    public static void main(String[] args){
        new BucketBallGame().doTransfers();
    }

    private void doTransfers(){
        for(int i=0; i < 10; i++){
            new Thread(new TransferThread(!RIGHT_TO_LEFT)).start();
            new Thread(new TransferThread(RIGHT_TO_LEFT)).start();
        }
    }

    public void transfer(boolean direction, int numToTransfer){
        if(direction == RIGHT_TO_LEFT){
            bucket[0] += numToTransfer;
            bucket[1] -= numToTransfer;
        }else{
            bucket[0] -= numToTransfer;
            bucket[1] += numToTransfer;
        }
        System.out.println("Bucket_Right: "+bucket[0]+" Bucket_Left: "+bucket[1]+" Total: "+(bucket[0]+bucket[1]));
    }

    private class TransferThread implements Runnable{
        private boolean direction;

        public TransferThread(boolean direction){
            this.direction = direction;
        }

        @Override
        public void run(){
            for(int i=0; i < 10; i++){
                transfer(direction, (int)(Math.random()*2000));
                try{
                    Thread.sleep((int)(Math.random()*100));
                }catch(InterruptedException ex){
                }
            }
        }
    }
}

但是运行的结果总和并不是常数20000,因为我梦并没有以原子单元来执行移出或者加入球的操作。解决的方法是在移动球是加一个同步关键字,如下:

public synchronized void transfer(boolean direction, int numToTransfer){

Java提供了特殊的等待/通知机制,以生产者/消费者问题为例:

public class ProducerConsumerGame{
    public static void main(String args[]){
        Bucket bucket = new Bucket();
        new Thread(new Producer(bucket)).start();
        new Thread(new Consumer(bucket)).start();
    }
}

final class Consumer implements Runnable{
    private Bucket bucket;

    public Consumer(Bucket bucket){
        this.bucket = bucket;
    }

    @Override
    public void run(){
        for(int i=0; i < 10; i++){
            bucket.get();
        }
    }
}

final class Producer implements Runnable{
    private Bucket bucket;

    public Producer(Bucket bucket){
        this.bucket = bucket;
    }

    @Override
    public void run(){
        for(int i=0; i < 10; i++){
            bucket.put((int)(Math.random()*100));
        }
    }
}

class Bucket{
    private int packOfBalls;
    private boolean available = false;

    public synchronized int get(){
        if(available == false){
            try{
                wait();
            }catch(InterruptedException e){
            }
        }
        System.out.println("Consumer got: "+packOfBalls);
        available = false;
        notify();
        return packOfBalls;
    }

    public synchronized void put(int packOfBalls){
        if(available){
            try{
                wait();
            }catch(InterruptedException e){
            }
        }
        this.packOfBalls = packOfBalls;
        available = true;
        System.out.println("Producer put: "+packOfBalls);
        notify();
    }
}

生产者/消费者模型在现实生活场景中可以观察到,譬如聊天程序。
何时进行同步

在多线程中,通常多个线程要对共享的数据进行操作,所以同步是必不可少的。synchronized语义保证在任意给定的时间内,只有一个线程能访问受保护区段。但这往往会带来性能问题。所以但多线程程序需要足够的同步以保护共享的数据又要避免他们受到破坏,但又不要过分的同步,可以考虑使用volatile关键字实现同步。

时间: 2024-08-01 06:33:12

Java线程初探的相关文章

java进阶06 线程初探

线程,程序和进程是经常容易混淆的概念. 程序:就是有序严谨的指令集 进程:是一个程序及其数据在处理机上顺序执行时所发生的活动 线程:程序中不同的执行路径,就是程序中多种处理或者方法. 线程有两种方法实现 一:继承Thread 覆盖run方法 package Thread; public class Thread1 { public static void main(String[] args){ MyThread1 thread1=new MyThread1(); thread1.setName

JAVA线程-join

概念 join方法,一种特殊的wait,当前运行线程调用另一个线程的join方法,当前线程进入阻塞状态直到调用join方法的线程结束,再继续执行. 一般情况下,都是主线程创建一个子线程,子线程调用join方法,主线程会进入阻塞状态,直到子线程运行结束. 简单案例 public class JoinThreadDemo { public static void main(String[] args) { JoinRunnable runnable1 = new JoinRunnable(); Th

java 线程详解

5月7号  周末看了一下线程方面的内容 ,边看视频边看书还附带着参考了很多人的博客,一天的收获,写下来整理一下:感觉收获还是挺多的:过段时间可能看完java  这几大块要去看一下关于spring boot  的内容顺便  也整理一下:附上我参考的 几本书: 关于java  线程,首先要了解一下线程和进程之间的关系.区别以及他们之间的概念: 首先是线程: 什么是线程? 线程是在程序执行过程中能够执行部分代码的一个执行单元,也看看做是一个轻量级的进程:线程是程序内的程序控制流只能使用程序内分配给程序

Java线程工作内存与主内存变量交换过程及volatile关键字理解

Java线程工作内存与主内存变量交换过程及volatile关键字理解 1. Java内存模型规定在多线程情况下,线程操作主内存变量,需要通过线程独有的工作内存拷贝主内存变量副本来进行.此处的所谓内存模型要区别于通常所说的虚拟机堆模型: 2. 线程独有的工作内存和进程内存(主内存)之间通过8中原子操作来实现,如下图所示: 原子操作的规则(部分): 1) read,load必须连续执行,但是不保证原子性. 2) store,write必须连续执行,但是不保证原子性. 3) 不能丢失变量最后一次ass

java线程

Java线程详解 1.操作系统中的线程和进程讲解: 现在的操作系统大都是多任务操作系统,多线程是多任务的一种. 进程是指操作系统中运行的一个程序,每个进程都有自己的一块内存空间,一个进程中可以启动多个线程. 线程是指进程中的一个执行流程,一个进程中可以运行多个线程.比如java.exe进程中可以运行很多线程.线程总是属于某个进程,进程中的多个线程共享进程的内存. “同时”执行是人的感觉,在线程之间实际上轮换执行. Java线程的两种具体实现方法: 第一种继承:具体代码实现如下: Public (

Java 线程第三版 第四章 Thread Notification 读书笔记

一.等待与通知 public final void wait() throws InterruptedException 等待条件的发生. public final void wait(long timeout) throws InterruptedException 等待条件的发生.如果通知没有在timeout指定的时间内发生,它还是会返回. public final void wait(long timeout, int nanos) throws InterruptedException

Java线程使用大全

1.线程实现 1.Thread类 构造方法: 案例代码: public class Ex10_1_CaseThread extends Thread {// 创建一个类继承(extend)Thread类 String studentName; public Ex10_1_CaseThread(String studentName) {// 定义类的构造函数,传递参数 System.out.println(studentName + "申请访问服务器"); this.studentNam

java线程五种状态

java线程五种状态: 创建 -> 就绪 -> 运行 -> 销毁 创建 -> 就绪 -> 运行 -> 等待(缺少资源) -> 销毁 下图:各种状态转换

java线程详细介绍

目录(?)[-] 一扩展javalangThread类 二实现javalangRunnable接口 三Thread和Runnable的区别 四线程状态转换 五线程调度 六常用函数说明 使用方式 为什么要用join方法 七常见线程名词解释 八线程同步 九线程数据传递 本文主要讲了java中多线程的使用方法.线程同步.线程数据传递.线程状态及相应的一些线程函数用法.概述等. 首先讲一下进程和线程的区别: 进程:每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销,一个进程包含1