点击此处查看最新的网赚项目教程
1. 基础介绍
线程有四种创建方式,但是我只记录两种,还有的创建方式是通过实现Callable接口,并且重写其中的call方法(有一点要注意,就是只有线程执行完毕才能收到返回值);
注意:一个简单的Java.exe应用程序,运行的话,其中至少有三个线程;一个main(主线程),一个gc()垃圾回收机制(垃圾回收线程,它的垃圾回收是自动的),还有一个异常处理线程;
2.线程的创建和使用
第一种创建线程的方法
//自己创建一个类继承Thread类;然后就重写其中的run方法;run方法中写你要执行的动作;
class testThread extends Thread {
// 重写run方法
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(“线程:”+Thread.currentThread().getName()+”:” + i);
public class ThreadCreate {
public static void main(String[] args) {
// 创建一个对象调用start方法,不过这个方法是Thread中的;
testThread t = new testThread();
t.start();
for (int j = 0; j < 1000; j++) {
System.out.println(“主线程:”+Thread.currentThread().getName()+”:” + j);
它的结果就证明了线程之间的运行是并发的,就是通过时间片来管理进行;不是一种顺序执行;
Thread中的常用方法:
2.第二种创建线程的方法
就是指写一个类实现Runnable接口,然后重写其中的run方法;需要执行的操作写在run方法中;
public class RunableText implements Runnable {
//重写Runnable中的方法,
@Override
public void run() {
for (int i = 0; i < 10; i++) {
/*
由于这个方法已经不是Thread类中的方法,而是Runnable
接口中的方法,在Runnable中没有getName等方法,所以只能直接通过Thread调用;
主要还是currentThread()是静态的返回一个Thread对象;
*/
System.out.println(Thread.currentThread().getName() + “:” + i);
public static void main(String[] args) {
// 创建一个实现Runnable接口的对象
RunableText runableText = new RunableText();
// 创建一个Thread对象,然后就是放入到Thread的构造方法中生成一个线程;
Thread thread = new Thread(runableText);
// 由于通过Thread类已经生成了一个线程;,于是就可以调用Thread线程中的方法;
thread.setName(“子线程”);
thread.start();//开启线程
Thread.currentThread().setName(“主线程”);
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + “:” + i);
上述程序运行结果:
2. 线程的调度
注意: 在Java中线程的优先级并非绝对的,尝试之后发现并非优先级高就可以先全部执行,只能说优先级越高,那么执行的概率越大;
线程的各种优先级,如下图:(不同的优先级就会有不同的执行顺序;)第一个是最低的优先级,第二个是默认优先级,第三个是最高优先级;
2.定义优先级的方法
上述代码执行的结果:
3. 线程的生命周期
线程的生命周期,是主要记录在线程的类Thread.State,
1.
2.
3.
4.
按照上面的图片稍作解释;
第一个new状态,就是指线程刚刚创立,还没有调用start方法的时候;
第二个 RUNNABLE,则是指线程目前处于可运行状态,在等待需要的资源,就像是操作系统中的就绪;
第三个 BLOCKED,这个不是很理解,等继续学习之后再看看吧,但是在网上看来一下,大概就是类似于阻塞;
第四个 WAITING,这个大概就是理解为使用了wait()方法进入等待状态之后;
第五个TIMED_WAITING,是指使用wait(long)方法,进入等待状态后;
TERMINATED;最后一个就是线程已经终结;生命到了尽头;
4. 线程的同步
有时候,比如卖票的时候,如果只是使用上面的基础线程肯定是不能达到要求的,会出现重票,甚至是负票的现象;如下面的问题程序:
public class RunTicket implements Runnable {
private static int ticket = 100;
@Override
public void run() {
while (ticket > 0) {
System.out.println(Thread.currentThread().getName() + “:” + ticket);
ticket–;
public static void main(String[] args) {
RunTicket run = new RunTicket();
Thread thread1 = new Thread(run);
Thread thread2 = new Thread(run);
Thread thread3 = new Thread(run);
thread1.setName(“窗口1”);
thread2.setName(“窗口2”);
thread3.setName(“窗口3”);
thread1.start();
thread2.start();
thread3.start();
运行结果:
那么为什么出票会出现重复?
首先可以知道线程的运行顺序是不规则的,你不能知道cpu并发线程中的哪些线程会运行,哪些线程会停止,当第一个线程对象的ticket(ticket=100)没有运行ticket–时,第二个线程就已经取到了ticket的值(这时ticket=100),这时就会发生所谓的重票现象,因为他们共用一个对象run,所以也就共用一个ticket;
解决办法:
同步代码块,使用synchronized对需要同步的代码进行修饰;在这里我们可以直接同步那些使用了ticket的代码,意思就是只有一个对线程对象可以使用,这就是使用同步监视器(或称锁)的方法进行同步;
public class RunTicket implements Runnable {
private int ticket = 100;
//创建一个公用的对象,当锁
Kmdog kmdog = new Kmdog();
@Override
public void run() {
while (true) {
//当然这里就是使用锁的地方,锁也不一定非要这样写,有时候可以用this,考虑使用当前类来做锁;
synchronized (kmdog) {
if (ticket > 0) {
System.out.println(Thread.currentThread().getName() + “:” + ticket);
ticket–;
} else {
break;
public static void main(String[] args) {
RunTicket run = new RunTicket();
Thread thread1 = new Thread(run);
Thread thread2 = new Thread(run);
Thread thread3 = new Thread(run);
thread1.setName(“窗口1”);
thread2.setName(“窗口2”);
thread3.setName(“窗口3”);
thread1.start();
thread2.start();
thread3.start();
class Kmdog {
最重要的是要使用公共的锁;
运行结果:
2. 通过同步方法;也可以达到上述的要求;详细请百度,不做赘述;
杂记,现学即现记(以后把所有东学西记的东西全部总结起来)
百度的时候没有意中看到,在子类的构造方法中可以通过super调用父类的普通方法,尝试了一下还真的可以;又get到了一个新东西;
父类中的方法要是没有throws异常,那么子类就没有法直接throws异常;为什么static不能修饰局部变量,因为它修饰的是全局变量;线程组:在java.lang.ThreadGroup类是用来定义一个线程组的;一个管理线程的类;每个线程都拥有自己独立的栈和程序计数器;多个线程共享一个进程中的方法区;接口与接口之间必须要通过extends继承,而不能通过implements实现;只有类才能实现接口;我发现其实所有继承了Runnable接口的B接口,都可以通过实现B,来创建线程;比如(RunnableFuture);
———END———
限 时 特 惠: 本站每日持续更新海量各大内部创业教程,一年会员只需98元,全站资源免费下载 点击查看详情
站 长 微 信: cai842612