黑马程序员-Java多线程操作

——Java培训、Android培训、iOS培训、.Net培训、期待与您交流!——-

Java中的线程

一个程序的运行需要启动一个应用进程,一个进程可以创建多个线程,帮助应用完成多任务操作,实现并发运行。在Java中线程是被封装成Thread类,进行多线程操作时只需要继承一个Thread类,实现自己的功能即可,然后开启此线程,或者你也可以实现一个Runnable接口,然后将其传递给Thread对象,然后再启动它。

线程的创建于启动

继承Thread

创建一个类并继承Thread类,然后实现Thread类的run方法,在run方法内填上自己的代码,然后创建这个自定义类,并调用其start方法来启动这个自定义线程。

// 引入Thread
import java.lang.Thread;

/**
 * 创建自己的Thread,实现run方法(放上自己要执行的内容)
 */
class MyThread extends Thread {

    /**
     * 覆盖超类Thread的run方法
     */
    public void run() {
        for(int i=0; i<10; i++) {
            System.out.println("第" + i + "次循环");
        }
    }
}
class ThreadDemo1 {
    public static void main(String[] args) {
        // 创建一个自定义线程,并且启动它
        new MyThread().start();
    }
}
/* 程序输出:
第0次循环
第1次循环
第2次循环
第3次循环
第4次循环
第5次循环
第6次循环
第7次循环
第8次循环
第9次循环
*/

实现Runnable

一个实现过Runnable的对象都可以被一个Thread对象所执行,

import java.lang.Thread;
import java.lang.Runnable;
/**
 * 创建一个类,实现Runnable接口。
 */
class MyRunnable implements Runnable {

    /**
     * 实现Runnable的run方法
     */
    public void run() {
        for(int i=0; i<5; i++) {
            System.out.println("Runable:第" + i + "次循环");
        }
    }
}
class ThreadDemo2 {
    public static void main(String[] args) {
        // 创建一个线程,并创建一个实现过Runnable的对象
        // 构造它,然后再启动这个线程
        new Thread(new MyRunnable()).start();
    }
}
/* 程序输出:
Runable:第0次循环
Runable:第1次循环
Runable:第2次循环
Runable:第3次循环
Runable:第4次循环
*/

synchronized的使用

既然是多线程,那么就会出现多线程的问题,如同时访问同一资源,从而产生意料之外的结果,这是我们所不想看到的。在Java中可以很简单的解决这个问题,使用synchronized对操作进行加锁,synchronized可以对对象加锁,也可以对函数进行加锁。下面对比一下未使用synchronized和使用synchronized的不同之处。

未使用synchronized的情况

import java.lang.Thread;
import java.lang.Runnable;

class MyRunnable implements Runnable {
    private static int i=0;
    public void run() {
        for(; i<10; i++) {
            try {
                Thread.sleep(10);
            } catch(Exception e) {

            }
            print(i);
        }
    }

    private void print(int k) {
        System.out.println(k);
    }
}

class Demo {
    public static void main(String[] args) {
        MyRunnable r = new MyRunnable();
        new Thread(r).start();
        new Thread(r).start();
    }
}

可以看到结果不正确,因为两个线程可能会同时进入线程,然后打印出两个相同的值。

0
0
2
3
4
5
6
7
8
9
10

使用了synchronized后的情况

import java.lang.Thread;
import java.lang.Runnable;

class MyRunnable implements Runnable {
    private static int i=0;
    public void run() {
        synchronized(this) {
            for(; i<10; i++) {
                try {
                    Thread.sleep(10);
                } catch(Exception e) {

                }
                print(i);
            }
        }
    }

    private void print(int k) {
        System.out.println(k);
    }
}

class Demo {
    public static void main(String[] args) {
        MyRunnable r = new MyRunnable();
        new Thread(r).start();
        new Thread(r).start();
    }
}

当对for进行加锁处理后,便不会同时两个线程进入循环,这样打印的数字便不会出错。

0
1
2
3
4
5
6
7
8
9

synchronized的加锁对象会有一个标志位(0/1),默认的情况下是0,当线程执行到synchronized的加锁对象后如果对象的标志位为0,那么将其设置为1,否则等待。这个标志位可以称之为“锁旗标”。这样以来便可以实现线程同步。

虽然synchronized解决了多线程的不安全问题,但是也是有一定的弊端的,它会降低程序的执行效率,所以,synchronized不可以随意放置,应尽量将其放到必须使用的位置上。如单例模式的一个例子:

public class Single {

    private Single mInstance;

    private Single(){

    }

    public static Single getInstance() {
        if(mInstance == null) {
            synchronized(Single.class) {
                if(mInstance == null) {
                    mInstance = new Single();
                }
            }
        }
        return mInstance;
    }
}

这里的synchronized可以加在getInstance()前面,但是这样会大大降低执行效率,也可以去掉外层的if(mInstance == null),但是这样也会增加不必要的判断,以为如果mInstance已经创建后便不需要锁了。若此以来,上面这种写法是最好的。最内层的if判断有必要说明一下,可以假设这样一种情况,两个线程都执行到第一个if的后面,那么,如果没有内层的if判断的话,mInstance会被创建两次,所以,内层的if是不可或缺的。

waitnotify的使用

waitnotify是Object对象中的两个方法,其作用是用于多线程中的控制,如想使用两个线程交替打印出OddEven时,具体代码如下:

import java.lang.Thread;
import java.lang.Runnable;

class Temp {
    public static boolean flag = false;
}

class Odd implements Runnable{

    public void run() {
        while(true) {
            if(Temp.flag) {
                try {
                    wait();
                } catch(Exception e) {}
            }
            System.out.println("Odd");
            Temp.flag = !Temp.flag;
            try {
                notify();
            } catch(Exception e) {}
        }
    }
}

class Even implements Runnable {

    public void run() {
        while(true) {
            if(!Temp.flag) {
                try {
                    wait();
                } catch(Exception e) {}
            }
            System.out.println("Even");
            Temp.flag = !Temp.flag;
            try {
                notify();
            } catch(Exception e) {}
        }
    }
}

class Demo {
    public static void main(String[] args) {
        new Thread(new Odd()).start();
        new Thread(new Even()).start();
    }
}

当然除了notify方法,还有notifyAll方法,用于唤醒所有线程。

Lock的使用

JDK1.5之后,也就是Java5.0之后,增加了许多新的内容,如用于线程控制的一些类,Lock的用法相当于synchronizedLocklock()unlock()分别用于加锁和解锁,一般使用方法如下:

import java.lang.Runnable;
import java.lang.Thread;
import java.util.concurrent.locks.*;

class Locks implements Runnable {
    private Lock lock = new ReentrantLock();
    private int index = 0;
    public void run() {
        while(true) {
            lock.lock();
            System.out.print(index + " ");
            try {
                Thread.sleep(100);
            } catch(Exception e) {}
            index ++;
            lock.unlock();
        }
    }
}

class Demo {
    public static void main(String[] args) {
        Locks locks = new Locks();
        new Thread(locks).start();
        new Thread(locks).start();
        new Thread(locks).start();
    }
}

这样便可以顺序打印出0 1 2 3 4 ···

通过Lock的对象,我们可以创建Condition对象,如

Condition condition = lock.newCondition();

然后可以使用condition.await();condition.signal()来暂停和唤醒线程,当然还有condition.signalAll()来唤醒所有线程。

时间: 2024-10-11 06:11:56

黑马程序员-Java多线程操作的相关文章

黑马程序员---Java多线程

---------------------- Android开发.java培训.期待与您交流! ---------------------- 线程与进程是程序运行中体现的两个名词,它包含这不同的程序域.进程指的是一个正在运行的程序,如:360,QQ运行时就是不同的两个进程.当你打开windows任务管理器时,看到的每个进程就是此时windows中正在运行的程序.线程则就是进程中的一个个独立的控制单元,线程控制着进程的执行,也就是说每个正在运行的程序中就包括着很多的线程. 主线程:Java虚拟机运

黑马程序员——java多线程基础知识1

多线程 进程是一个正在执行的程序. cpu在同时执行这些程序,其实是跳跃式的,做快速的切换,时间很短.一个进程可能存在多条路径.迅雷的多路径.每一个进行执行都有一个执行顺序,该顺序是一个执行路径,或这叫一个控制单元.每一个进程至少有一个线程,线程就是进程中的一个独立的控制单元,线程控制进程的执行.jvm启动的时候会有一个进程就叫做java,exe,该进程中至少有一个线程在控制Java程序的执行 ,而且该线程的执行代码在 主函数中.该线程称为主线程.虚拟机至少也有两个线程,一个主线程执行,另一个负

黑马程序员——Java多线程基础知识2

多线程协同 线程间的通讯:我们对资源的操作动作不同,比如说两个卡车一个拉煤一个装煤.但是他们共享了一个资源. 怎么样把这个资源拿出来?怎样把车装满?这个资源当然是一个类,他里面的组成元素就是对象!!现在我们就要有操作对象的思想了,我用对象把这车装满,现在一车装一个对象. 等待唤醒机制: 用的不是sleep是wait.flag标记,这是两人沟通的方式.其实每个标记就要做一次等待或者notify,判断wait,改值notify.线程池.notify唤醒里面的线程,按顺序唤醒.wait和notify必

黑马程序员——Java多线程

多线程基础知识 进程是一个正在执行的程序. cpu在同时执行这些程序,其实是跳跃式的,做快速的切换,时间很短.一个进程可能存在多条路径.迅雷的多路径.每一个进行执行都有一个执行顺序,该顺序是一个执行路径,或这叫一个控制单元.每一个进程至少有一个线程,线程就是进程中的一个独立的控制单元,线程控制进程的执行..jvm启动的时候会有一个进程就叫做java.exe,该进程中至少有一个线程在控制Java程序的执行 ,而且该线程的执行代码在 主函数中.该线程称为住线程.虚拟机至少也有两个线程,一个主线程执行

黑马程序员-JAVA多线程总结

------<a href="http://www.itheima.com" target="blank">Java培训.Android培训.iOS培训..Net培训</a>.期待与您交流! ------- JAVA多线程实现方式主要有三种:继承Thread类.实现Runnable接口.使用ExecutorService.Callable.Future实现有返回结果的多线程.其中前两种方式线程执行完后都没有返回值,只有最后一种是带返回值的.

黑马程序员---Java多线程的用法详解

------- android培训.java培训.期待与您交流! ---------- Java线程详解 一.操作系统中线程和进程的概念 现在的操作系统是多任务操作系统.多线程是实现多任务的一种方式. 进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程中可以启动多个线程.比如在Windows系统中,一个运行的exe就是一个进程. 线程是指进程中的一个执行流程,一个进程中可以运行多个线程.比如java.exe进程中可以运行很多线程.线程总是属于某个进程,进程中的多个线程

黑马程序员-Java多线程篇《四》

                         ------- android培训.java培训.期待与您交流! ---------- 1.线程和进程的概念 1.1.进程(Process):拥有独立的内存空间,每个独立执行的程序称为进程   1.2.线程(Thread):线程是一个程序内部的一条执行路径,Java虚拟机允许应用程序并发地运行多个执行线程   1.3.线程和进程的区别           每个进程都有独立的代码和数据空间(进程上下文),进程间的切换开销大           线程

黑马程序员-Java多线程《四》

                         ------- android培训.java培训.期待与您交流! ---------- 1.线程和进程的概念 1.1.进程(Process):拥有独立的内存空间,每个独立执行的程序称为进程   1.2.线程(Thread):线程是一个程序内部的一条执行路径,Java虚拟机允许应用程序并发地运行多个执行线程   1.3.线程和进程的区别           每个进程都有独立的代码和数据空间(进程上下文),进程间的切换开销大           线程

黑马程序员————java多线程及同步机制

------<a href="http://www.itheima.com" target="blank">Java培训.Android培训.iOS培训..Net培训</a>.期待与您交流! ------- 1.理解程序.进程.线程的概念程序可以理解为静态的代码,计算机指令的集合,它以文件的形式存储在磁盘上.进程可以理解为执行中的程序,一个单独程序打开了单独的一段地址空间进行单独的工作.线程可以理解为进程的进一步细分,程序的一条执行路径. 多