Java基础知识回顾--线程

基本概念
线程是一个程序内部的顺序控制流

Java的线程是通过java.lang.Thread类来实现的。main函数是一个主线程,用户可以通过创建Thread的实例来创建新的线程。每一个线程都必须实现run方法。通过Thread类的start方法来启动一个线程。

两种方式实现,一种是线程类实现Runnable接口;二种就是定义一个Thread的子类并重写其run方法。

public class TestThread1 {
    public static void main(String args[]) {
        Runner1 r = new Runner1();
        r.start();
        //r.run();
        //Thread t = new Thread(r);
        //t.start();

        for(int i=0; i<100; i++) {
            System.out.println("Main Thread:------" + i);
        }
    }
}

//class Runner1 implements Runnable {
class Runner1 extends Thread {
    public void run() {
        for(int i=0; i<100; i++) {
            System.out.println("Runner1 :" + i);
        }
    }
}

以下是几个线程控制的基本方法

用stop或者其他方法直接切断线程是很暴力的是很不好的,这里介绍一种比较好的结束线程的办法。巧妙的用到一个flag。

public class TestThread4 {
    public static void main(String args[]){
        Runner4 r = new Runner4();
        Thread t = new Thread(r);
        t.start();
        for(int i=0;i<100000;i++){
            if(i%10000==0 & i>0)
                System.out.println("in thread main i=" + i);
        }
        System.out.println("Thread main is over");
        r.shutDown();
        //t.stop();
    }
}

class Runner4 implements Runnable {
  private boolean flag=true;

    public void run() {
        int i = 0;
        while (flag==true) {
            System.out.print(" " + i++);
        }
    }

  public void shutDown() {
        flag = false;
  }
}

线程同步
线程同步这个问题很重要,会衍生很多锁的问题。也是两种方式上锁,一种是直接在方法上上锁,另一种就是锁对象。

public class TestSync implements Runnable {
  Timer timer = new Timer();
  public static void main(String[] args) {
    TestSync test = new TestSync();
    Thread t1 = new Thread(test);
    Thread t2 = new Thread(test);
    t1.setName("t1");
    t2.setName("t2");
    t1.start();
    t2.start();
  }
  public void run(){
    timer.add(Thread.currentThread().getName());
  }
}

class Timer{
  private static int num = 0;
  public synchronized void add(String name){
    //synchronized (this) {
        num ++;
        try {Thread.sleep(1);}
        catch (InterruptedException e) {}
        System.out.println(name+", 你是第"+num+"个使用timer的线程");
      //}
  }
}

死锁
假如两个线程都需要两个资源才能完成,A线程把a资源锁定等待b资源,B线程把b资源锁定等待a资源。这样就会形成死锁,所以我们要把锁定义到最大化就是锁定整个对象,就是专业术语说锁的粒度要尽量大。

public class TT implements Runnable {
    int b = 100;

    public synchronized void m1() throws Exception{
        //Thread.sleep(2000);
        b = 1000;
        Thread.sleep(5000);
        System.out.println("b = " + b);
    }

    public void m2() throws Exception{
        Thread.sleep(2500);
        b = 2000;
    }

    public void run() {
        try {
            m1();
        } catch(Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws Exception {
        TT tt = new TT();
        Thread t = new Thread(tt);
        t.start();

        tt.m2();
        System.out.println(tt.b);
    }
}

这个程序段输出的结果是
2000
b = 2000
这段程序也是先进的m2。

package yanning;

public class TT implements Runnable {
    int b = 100;

    public synchronized void m1() throws Exception{
        System.out.println(2);
        //Thread.sleep(2000);
        b = 1000;
        Thread.sleep(5000);
        System.out.println("b = " + b);
    }

    public synchronized void m2() throws Exception {
        System.out.println(1);
        Thread.sleep(2500);
        b = 2000;
    }

    public void run() {
        try {
            m1();
        } catch(Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws Exception {
        TT tt = new TT();
        Thread t = new Thread(tt);
        t.start();

        tt.m2();
        System.out.println(tt.b);
    }
}

这段代码输出的结果是
1
2000
2
b = 1000

package yanning;

public class TT implements Runnable {
    int b = 100;

    public synchronized void m1() throws Exception{
        //System.out.println(2);
        //Thread.sleep(2000);
        b = 1000;
        Thread.sleep(5000);
        System.out.println("b = " + b);
    }

    public synchronized void m2() throws Exception {
        //System.out.println(1);
        Thread.sleep(2500);
        b = 2000;
    }

    public void run() {
        try {
            m1();
        } catch(Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws Exception {
        TT tt = new TT();
        Thread t = new Thread(tt);
        t.start();

        tt.m2();
        System.out.println(tt.b);
    }
}

这一段代码执行结果是
1000
b = 1000
锁是锁住了,但是tt那个线程执行的快一些,先进入了m2。

所以说线程同步是一个很复杂的问题,我们得仔细推敲。而且我个人觉得跟电脑的运行速度还是有关系的。其他线程可以自由访问没有加同步的任何方法,并且会产生数据不一致的现象。如果要保护好某一类的同步对象,必须要对该对象所有的方法考虑加不加同步,加了同步很有可能效率会变低,不加同步很有可能造成数据不一致的现象。

优先级
我的理解就是CPU优先让哪个线程执行嘛,比较单CPU其实是假的多线程,就是因为CPU运算速度比较快,所以就一个线程让你执行一下,就像是多线程在执行一样。

生产者与消费者问题【经典问题】


public class ProducerConsumer {
    public static void main(String[] args) {
        SyncStack ss = new SyncStack();
        Producer p = new Producer(ss);
        Consumer c = new Consumer(ss);
        new Thread(p).start();
        new Thread(c).start();
    }
}

class WoTou {
    int id;
    WoTou(int id) {
        this.id = id;
    }
    public String toString() {
        return "WoTou : " + id;
    }
}

class SyncStack {
    int index = 0;
    WoTou[] arrWT = new WoTou[6];

    public synchronized void push(WoTou wt) {
        while(index == arrWT.length) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        this.notifyAll();
        arrWT[index] = wt;
        index ++;
    }

    public synchronized WoTou pop() {
        while(index == 0) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        this.notifyAll();
        index--;
        return arrWT[index];
    }
}

class Producer implements Runnable {
    SyncStack ss = null;
    Producer(SyncStack ss) {
        this.ss = ss;
    }

    public void run() {
        for(int i=0; i<20; i++) {
            WoTou wt = new WoTou(i);
            ss.push(wt);
System.out.println("生产了:" + wt);
            try {
                Thread.sleep((int)(Math.random() * 200));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

class Consumer implements Runnable {
    SyncStack ss = null;
    Consumer(SyncStack ss) {
        this.ss = ss;
    }

    public void run() {
        for(int i=0; i<20; i++) {
            WoTou wt = ss.pop();
System.out.println("消费了: " + wt);
            try {
                Thread.sleep((int)(Math.random() * 1000));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
时间: 2024-08-01 00:27:07

Java基础知识回顾--线程的相关文章

Java基础知识回顾,看看你们忘了多少

1.Java中成员变量又分为实例成员变量 和类成员变量. 2.写类的目的是为了描述一类事物共有的属性 和功能.3.成员变量和局部变量的类型可以是Java中的任何一种数据类型 .4.用修饰符 static 说明的成员变量是类变量.5.变量的名字与成员变量的名字相同,则成员变量被隐藏 ,该成员变量在这个方法内暂时失效.6.用修饰符static说明的成员变量是类变量 .7.如果局部变量的名字与成员变量的名字相同,成员变量 将被隐藏.8.方法定义包括两部分:方法声明 和方法体.9.在Java中,当一个方

Java基础知识回顾--正则表达式

RegularExpressions 字符串处理利器 正则表达式语法 正则表达式包括普通字符(例如,a 到 z 之间的字母)和特殊字符(称为"元字符"). 特殊字符 下表包含了单字符元字符的列表以及它们在正则表达式中的行为. 若要匹配这些特殊字符之一,必须首先转义字符,即,在字符前面加反斜杠字符 (). 例如,若要搜索"+"文本字符,可使用表达式"+". 元字符 下表包含了多字符元字符的列表以及它们在正则表达式中的行为. 非打印字符 下表包含表示

Java基础知识回顾--网络编程基础

OSI参考模型 TCP/IP参考模型 应用层 表示层 应用层 会话层 传输层 传输层 网络层 网络层 数据链路层 物理+数据链路层 物理层 IP协议 最大的贡献就是给大家提供了独一无二的IP地址. A类地址 8位网络号并且0打头,24位主机号: B类地址 16位网络号并且10打头,16位主机号: C类地址 24位网络号并且110打头,8位主机号: D类地址 1110打头,多播地址: E类地址 1111打头,保留为今后使用. Socket /** *Server端 **/ import java.

Java基础知识回顾--反射机制

Reflection ClassLoader的类加载机制 并非一次性加载. 需要的时候加载(运行期间动态加载). java-verbose:class可以观察类的具体加载过程. static语句块在加载后执行一次. dynamic语句块每次new新的对象都会执行,等同于构造方法中语句,用得也比较少. 首先bootstrap class loader把其他的Class loader给load进来,然后不同的class loader去load不同的class. public class TestCl

C#基础知识回顾--线程传参

在不传递参数情况下,一般大家都使用ThreadStart代理来连接执行函数,ThreadStart委托接收的函数不能有参数, 也不能有返回值.如果希望传递参数给执行函数,则可以使用带参数的ParameterizedThreadStart委托,           public delegate void ParameterizedThreadStart(Object obj) 可以将要传送给线程函数的信息封装为一个对象,然后调用Thread类的以下构造函数           public Th

J2ME中需要的Java基础知识

现在有大部分人,都是从零开始学J2ME的,学习J2ME的时候,总是从Java基础开始学习,而且现在讲Java基础的书籍中都是以J2SE来讲基础,这就给学习造成了一些不必要的麻烦,下面将J2ME中用到的和不需要的Java基础知识做一个简单的说明:        J2ME中使用到的Java基础知识: 1.  Java语法基础:包括基本数据类型.关键字.运算符等等 2.  面向对象的思想:类和对象的概念,继承和多态等等. 3.  异常处理 4.  多线程 J2ME中没有用到的Java基础知识: 1. 

javaeye基础-java基础知识问题求助

问题描述 java基础知识问题求助 问 形如 X(父类) y=new Y(子类): 这样new出来的对象y是子类对象还是父类对象? 如果子类有重载的构造函数,那么在new的时候父类的默认构造函数还会被子类的构造函数调用么? 解决方案 你可以去了解下向上转型和向下转型的区别! 解决方案二: java的一些基础知识 .Java基础知识一Java_计算机基础知识 解决方案三: new 出来的当然是子类对象,但是是父类引用,即父类引用指向之类对象. 子类有重载的构造函数?构造函数是不能重载的 解决方案四

《非常网管:网络管理从入门到精通(修订版)》——第1章 网络基础知识回顾1.1 计算机网络基础

第1章 网络基础知识回顾 古语云:"练武不练功,到老一场空",学习网络的基础理论就像练功一样重要.本章主要介绍网络的基础.网络的体系结构.ISO/OSI(International Standard Organization/Open System Interconnection,国际标准化组织提出的开放系统互联)参考模型.TCP/IP(Transmission Control Protocol/Internet Protocol,传输控制协议/网际协议),其间穿插大量的实验和技巧,有

Java基础之008-多线程

Java基础之008-多线程                                        35岁学习Java 1.进程和线程的概念. 1)     概念                 进程:正在进行中的程序(直译).                             线程:就是进程中一个负责程序执行的控制单元(执行路径)                 任务:每一个线程都有自己运行的内容.这个内容可以称为线程要执行的任务.                 提示:一个进程