Java线程基本概念和一个小栗子

线程历来是软件开发的一个很重要的组成部分,很多地方会用到线程。本博 Web 部分做的比较多,比如后台的 Socket,连接池之类的,现在转到 Android,那线程用得更普遍了。

今天记录一篇线程的概念记录,主要是简单的 Java application,关注线程本身。未来再写点 Android部分的吧,因为Android的线程还是用得比较多,比较有趣的。

线程概念

先讲一个Java实现线程的机制,Monitor。

Monitor 是一个在 Java 应用程序生命周期中,所存在的对于资源的监护工具。她保证被保护的数据或者代码,在同一时刻被单独一个线程访问。

先上个图

Mou icon

中间区域,被活动线程占有,因此该线程变为资源的 Owner

Wait Set 部分是等待着的线程

Entry Set 是在排队的线程

因此,关系就很明白,Entry Set 根据某些规则排队,活动线程释放资源后,Entry Set 中的某个线程,变为活动线程,或者, 因为某些条件未满足,就被丢进 Wait Set,然后就被等着条件满足再变成活动线程。

Java 线程实现

Java 虚拟机中, 每个对象和类关联着 Monitor, 这些需要保护的资源,关联这一个锁。

多线程系统中,线程必须获得资源的锁,才能访问资源,所以说要等待活动线程释放锁才行。Java 使用关键字 synchronized 来控制锁。

一个小栗子

来个原子类,有个静态整型counter,为了显示方便,做个文件写入, 并且是个 synchronized 的方法 writeLog(),功能是 counter 计数后存文件。

public class DemoAtom {
    public static int counter = 0;
    public static synchronized void writeLog() {
        String filePath = "/path/to/somefile/file.txt";
        File file = new File(filePath);
        try {
            if (!file.exists()) {
                file.createNewFile();
            }
            FileWriter fstream = new FileWriter(filePath, true);
            BufferedWriter out = new BufferedWriter(fstream);
            String outLine = "Now counter is === " + Integer.toString(++DemoAtom.counter);
            out.write(outLine);
            out.newLine();
            out.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

线程类 1, 这里使用继承 Thread的方式,必须要重写 run 方法

public class DemoHelloThread extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            try {
                DemoAtom.writeLog();
                Thread.sleep(500L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

线程类2 , 这里换了种方式,使用了实现 Runnable 的方式,实现了 run 方法

public class DemoRunThread implements Runnable {
    public void run() {
        for (int i = 0; i < 5; i++) {
            try {
                DemoAtom.writeLog();
                Thread.sleep(500L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

Main 类,比较简单,尝试的时候,可以去掉 DemoAtom 中的 writeLog 方法的 synchronized 关键字,会发现输出的数字不同,有 synchronized 关键字的是顺序的,因为,再被不同线程访问时,JVM 加了锁,保证 DemoAtom 不被其他线程占有。

public class MainDemo {
    public static void main(String args[]) {
        System.out.println("Now starting thread demo");
        new DemoHelloThread().start();
        new Thread(new DemoRunThread()).start();
        System.out.println("Now ending thread demo");
    }
}