多线程的引入

线程:线程是程序执行的一条路径, 一个进程中可以包含多条线程;多线程并发                 执行可以提高程序的效率, 可以同时完成多项工作

多线程的应用场景

红蜘蛛同时共享屏幕给多个电脑

迅雷开启多条线程一起下载

QQ同时和多个人一起视频

服务器同时处理多个客户端请求

多线程并行和并发的区别

·并行就是两个任务同时运行,就是甲任务进行的同时,乙任务也在进行。(需              要多核CPU)

·并发是指两个任务都请求运行,而处理器只能按受一个任务,就把这两个任务安        排轮流进行,由于时间间隔较短,使人感觉两个任务都在运行。

·比如我跟两个网友聊天,左手操作一个电脑跟甲聊,同时右手用另一台电脑跟乙        聊天,这就叫并行。

·如果用一台电脑我先给甲发个消息,然后立刻再给乙发消息,然后再跟甲聊,再        跟乙聊。这就叫并发。

Java程序运行原理和JVM的启动是多线程的吗

Java程序运行原理:Java命令会启动java虚拟机,启动JVM,等于启动了一个                    应用程序,也就是启动了一个进程。该进程会自动启动一个 “主线程” ,然后          主线程去调用某个类的 main 方法。

JVM的启动是多线程的吗:JVM启动至少启动了垃圾回收线程和主线程,所以是多            线程的。

多线程程序实现的方式1

继承Thread:

定义类继承Thread

重写run方法

把新线程要做的事写在run方法中

创建线程对象

开启新线程, 内部会自动执行run方法

public class ThreadDemo {

public static void main(String[] args) {

//4,创建自定义类的对象

MyThreadmt = new MyThread();

//5,开启线程

mt.start();

//主线程和子线程会交替执行

for(int i=0;i<1000;i++){

System.out.println("bb");

}

}

}

//1,定义类继承Thread

class MyThread extends Thread{

//2,重写run方法

@Override

public void run() {

//3,将要执行的代码,写在run方法中

for(int i=0;i<1000;i++){

System.out.println("aaaaaaaaa");

}

}

}

多线程程序实现的方式2

实现Runnable

定义类实现Runnable接口

实现run方法

把新线程要做的事写在run方法中

创建自定义的Runnable的子类对象

创建Thread对象, 传入Runnable

调用start()开启新线程, 内部会自动调用Runnable的run()方法

public class ThreadDemo1 {

public static void main(String[] args) {

//4,创建自定义对象

MyRunnablemr = new MyRunnable();

//5,将其当作参数传递给Thread的构造函数

Threadt = new Thread(mr);

//6,开启线程

t.start();

for(int i = 0; i < 1000; i++) {

System.out.println("bb");

}

}

}

//1,定义一个类实现Runnable接口

class MyRunnable implements Runnable{

//2,重写run方法

@Override

public void run() {

//3,将要执行的代码写在run方法中

for(int i=0;i<1000;i++){

System.out.println("aaaaaaaaa");

}

}

}

实现Runnable的原理

1,看Thread类的构造函数,传递了Runnable接口的引用

2,通过init()方法找到传递的target给成员变量的target赋值

3,查看run方法,发现run方法中有判断,如果target不为null就会调用                   Runnable接口子类对象的run方法

多线程两种方式的区别

查看源码的区别:

a.继承Thread : 由于子类重写了Thread类的run(), 当调用start()时,                   直接找子类的run()方法

b.实现Runnable : 构造函数中传入了Runnable的引用, 成员变量记住了                  它, start()调用run()方法时内部判断成员变量Runnable的引用是否               为空, 不为空编译时看的是Runnable的run(),运行时执行的是子类的                   run()方法

继承Thread

好处是:可以直接使用Thread类中的方法,代码简单

弊端是:如果已经有了父类,就不能用这种方法

实现Runnable接口

好处是:即使自己定义的线程类有了父类也没关系,因为有了父类也可以实现                    接口,而且接口是可以多实现的

弊端是:不能直接使用Thread中的方法需要先获取到线程对象后,才能得到                Thread的方法,代码复杂

匿名内部类实现线程的两种方式

继承Thread类

//1,new 类(){}继承这个类

new Thread() {

//2,重写run方法

public void run() {

//3,将要执行的代码,写在run方法中

for(int i = 0; i < 3000; i++) {

System.out.println("aaaaa");

}

}

}.start();//4,开启线程

实现Runnable接口

//1,new 接口(){}实现这个接口

new Thread(new Runnable(){

//2,重写run方法

public void run() {

//3,将要执行的代码,写在run方法中

for(int i = 0; i < 3000; i++) {

System.out.println("bb");

}

}

}).start();//4,开启线程

线程获取名字和设置名字

获取名字:通过getName()方法获取线程对象的名字

设置名字:通过构造函数可以传入String类型的名字

设置名字方法一:

new Thread("xxx") {// 通过构造法方法给线程设置名字

public void run() {

for (int i = 0; i < 1000; i++) {

// 匿名内部类调用

// 通过getName方法获取线程名字

System.out.println(this.getName() + "....aaaaa");

}

}

}.start();

设置名字方法二:

new Thread() {

public void run() {

// 通过setName方法设置线程名字

this.setName("yyy");

for (int i = 0; i < 1000; i++) {

// 通过getName方法获取线程名字

System.out.println(this.getName() + "....bb");

}

}

}.start();

设置名字方法三:

Threadt = new Thread() {

public void run() {

for (int i = 0; i < 1000; i++) {

// 通过getName方法获取线程名字

System.out.println(this.getName() + "....bb");

}

}

};

// 通过setName方法设置线程名字

t.setName("zzz");

t.start();

获取当前线程的对象

new Thread(){

public void run() {

for(int i = 0; i < 1000; i++) {

//获取当前线程对对象

System.out.println(Thread.currentThread().

getName()+ "...aaaaaaaaa");

}

}

}.start();

new Thread(new Runnable() {

public void run() {

for(int i = 0; i < 1000; i++) {

//获取当前线程对象                  System.out.println(Thread.currentThread().

getName()+ "...bb");

}

}

}).start();

//获取主函数线程的引用,并改名字

Thread.currentThread().setName("我是主线程");

//获取主函数线程的引用,并获取名字

System.out.println(Thread.currentThread().

getName());

休眠线程

Thread.sleep(毫秒), 控制当前线程休眠若干毫秒

new Thread() {

public void run() {

for(int i = 0; i < 10; i++) {

System.out.println(getName() + "...aaaaaaaa");

try {

//当前线程睡眠10毫秒

Thread.sleep(10);

}catch (InterruptedException e) {

e.printStackTrace();

}

}

}

}.start();

new Thread() {

public void run() {

for(int i = 0; i < 10; i++) {

System.out.println(getName() + "...bb");

try {

//当前线程睡眠10毫秒

Thread.sleep(10);

}catch (InterruptedException e) {

e.printStackTrace();

}

}

}

}.start();

守护线程

setDaemon(), 设置一个线程为守护线程, 该线程不会单独执行, 当其他非守  护线程都执行结束后, 自动退出

Thread t1 = new Thread() {

public void run() {

for(int i = 0; i < 50; i++) {

System.out.println(getName() + "...aaaaaa");

try {

Thread.sleep(10);

}catch (InterruptedException e) {

e.printStackTrace();

}

}

}

};

Threadt2 = new Thread() {

public void run() {

for(int i = 0; i < 5; i++) {

System.out.println(getName() + "...bb");

try {

Thread.sleep(10);

}catch (InterruptedException e) {

e.printStackTrace();

}

}

}

};

//设置守护线程必须在thread.start()之前设置

//不能把正在运行的常规线程设置为守护线程

//传入true将t1设置为守护线程,

t1.setDaemon(true);

t1.start();

t2.start();

加入线程

join(), 当前线程暂停, 等待指定的线程执行结束后, 当前线程再继续

join(int), 可以等待指定的毫秒之后继续

final Thread t1 = new Thread() {

public void run() {

for(int i = 0; i < 50; i++) {

System.out.println(getName() + "...aaaaaa");

try {

Thread.sleep(10);

}catch (InterruptedException e) {

e.printStackTrace();

}

}

}

};

Threadt2 = new Thread() {

public void run() {

for(int i = 0; i < 50; i++) {

if(i == 2) {

try {

//插队,加入,直至t1线程全部执行完成

//t1.join();

//加入,有固定的时间,过了固定时间,继续交替执行

t1.join(30);

Thread.sleep(10);

}catch (InterruptedException e) {

e.printStackTrace();

}

}

System.out.println(getName() + "...bb");

}

}

};

t1.start();

t2.start();

礼让线程

public class ThreadDemo3 {

public static void main(String[] args) {

new MThread().start();

new MThread().start();

}

}

class MThread extends Thread {

@Override

public void run() {

for (int i = 0; i < 1000; i++) {

if (i % 10 == 0) {

//礼让线程,让出线程,但不一定有效果,线程执行由cup调度

Thread.yield();

}

System.out.println(getName() + "...." + i);

}

}

}

设置线程的优先级

setPriority()设置线程的优先级(效果不明显,因为线程调度是由cpu决定的)

Thread t1 = new Thread() {

@Override

public void run() {

for (int i = 0; i < 100; i++) {

System.out.println(getName() + "...aaaaa");

}

}

};

Threadt2 = new Thread() {

@Override

public void run() {

for (int i = 0; i < 100; i++) {

System.out.println(getName() + "...bb");

}

}

};

// 设置线程优先级,最大是10,最小是1,默认是5,

//可以给int值[1,10],也可以用Thread的常量

// t1.setPriority(10);

// t2.setPriority(1);

t1.setPriority(Thread.MIN_PRIORITY);

t2.setPriority(Thread.MAX_PRIORITY);

t1.start();

t2.start();

多线程同步代码块

什么情况下需要同步

a,当多线程并发, 有多段代码同时执行时, 我们希望某一段代码执行的过程                         中CPU不要切换到其他线程工作. 这时就需要同步.

b,如果两段代码是同步的, 那么同一时间只能执行一段, 在一段代码没执行                         结束之前, 不会执行另外一段代码.

同步代码块

a,使用synchronized关键字加上一个锁对象来定义一段代码, 这就叫同步               代码块

b,多个同步代码块如果使用相同的锁对象, 那么他们就是同步的

public class ThreadDemo5 {

public static void main(String[] args) {

final Printer p = new Printer();

new Thread() {

@Override

public void run() {

while (true) {

p.print1();

}

}

}.start();

new Thread() {

@Override

public void run() {

while (true) {

p.print2();

}

}

}.start();

}

}

class Demo {}

class Printer {

Demo d = new Demo();

public void print1() {

// 锁对象可以是任意对象,但是被锁的代码需要保证是同一把锁,      //不能用匿名对象

synchronized (d) {

System.out.print("好");

System.out.print("好");

System.out.print("学");

System.out.print("习");

System.out.print("\r\n");

}

}

public void print2() {

synchronized (d) {

System.out.print("天");

System.out.print("天");

System.out.print("向");

System.out.print("上");

System.out.print("\r\n");

}

}

}

多线程同步方法

使用synchronized关键字修饰一个方法, 该方法中所有的代码都是同步的

public class ThreadDemo6 {

public static void main(String[] args) {

final Printer2 p = new Printer2();

new Thread() {

@Override

public void run() {

while (true) {

p.print1();

}

}

}.start();

new Thread() {

@Override

public void run() {

while (true) {

p.print2();

}

}

}.start();

}

}

class Printer2 {

//非静态的同步方法的锁对象:this

//静态的同步方法的锁对象不可能是this(静态方法是优选于类对象存在[静态方法比类要先加载])

//静态的同步方法的锁对象:该类的字节码对象(.class文件)

//同步方法只需在方法上添加synchronized关键字即可

public static synchronized void print1() {

System.out.print("好");

System.out.print("好");

System.out.print("学");

System.out.print("习");

System.out.print("\r\n");

}

public static void print2() {

synchronized (Printer2.class) {

System.out.print("天");

System.out.print("天");

System.out.print("向");

System.out.print("上");

System.out.print("\r\n");

}

}

}

线程安全问题

多线程并发操作同一数据时, 就有可能出现线程安全问题,使用同步技术可以解      决这种问题, 把操作数据的代码进行同步, 不要多个线程一起操作

使用继承Thread

public class ThreadDemo7 {

public static void main(String[] args) {

TicketsSellert1 = new TicketsSeller();

TicketsSellert2 = new TicketsSeller();

TicketsSellert3 = new TicketsSeller();

TicketsSellert4 = new TicketsSeller();

t1.setName("窗口1");

t2.setName("窗口2");

t3.setName("窗口3");

t4.setName("窗口4");

t1.start();

t2.start();

t3.start();

t4.start();

}

}

class TicketsSeller extends Thread {

private static int tickets = 100;

//成员变量作为锁对象,必须保证所用的锁是同一个,不然无效

static Object obj = new Object();

public TicketsSeller() {

super();

}

public TicketsSeller(String name) {

super(name);

}

public void run() {

while(true) {

//        synchronized(obj){

synchronized(TicketsSeller.class) {

if(tickets <= 0)

break;

try {

//线程1睡,线程2睡,线程3睡,线程4睡

Thread.sleep(10);

}catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println(getName() + "...这是第" + tickets-- + "号票");

}

}

}

}

实现Runnable接口

public class ThreadDemo8 {

public static void main(String[] args) {

MyTicketmt = new MyTicket();

new Thread(mt,"窗口1").start();

new Thread(mt,"窗口2").start();

new Thread(mt,"窗口3").start();

new Thread(mt,"窗口4").start();

}

}

class MyTicket implements Runnable {

private int tickets = 100;

public void run() {

while(true) {

//可以使用this,因为只创建了一个对象,也就是说共用了一个锁对象

//        synchronized(this){

synchronized(MyTicket.class) {

if(tickets <= 0)

break;

try {

Thread.sleep(10);

}catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println(Thread.currentThread().getName()+ "...这是第" + tickets-- + "号票");

}

}

}

}

死锁

多线程同步的时候, 如果同步代码嵌套, 使用相同锁, 就有可能出现死锁,尽量    不要嵌套使用

private static String s1 = "筷子左";

private static String s2 = "筷子右";

public static void main(String[] args) {

new Thread() {

public void run() {

while(true) {

synchronized(s1) {

System.out.println(getName() +

"...拿到" + s1 + "等待" + s2);

synchronized(s2) {

System.out.println(getName() +

"...拿到" + s2 + "开吃");

}

}

}

}

}.start();

new Thread() {

public void run() {

while(true) {

synchronized(s2) {

System.out.println(getName() +

"...拿到" + s2 + "等待" + s1);

synchronized(s1) {

System.out.println(getName() +

"...拿到" + s1 + "开吃");

}

}

}

}

}.start();

}

以前的线程安全的类回顾

Vector,StringBuffer,Hashtable,Collections.synchroinzed(xxx)

Vector是线程安全的,ArrayList是线程不安全的

StringBuffer是线程安全的,StringBuilder是线程不安全的

Hashtable是线程安全的,HashMap是线程不安全的

单例设计模式

单例设计模式:保证类在内存中只有一个对象

如何保证类在内存中只有一个对象呢?

(1)控制类的创建,不让其他类来创建本类的对象。private

(2)在本类中定义一个本类的对象。Singleton s;

(3)提供公共的访问方式。  public static Singleton                                      getInstance(){returns}

单例写法两种:

(1)饿汉式 开发用这种方式

//饿汉式(不管用不用都创建对象)

      class Singleton{

//1,私有构造器,其他类不能访问该构造方法

privateSingleton(){}

//2,创建本类对象

private static Singleton s = new Singleton();

//3,对外提供公共的访问方法

public static Singleton getInstance(){

return s;

}

public static void print(){

System.out.println("------------");

}

}

(2)懒汉式 面试写这种方式。多线程的问题?

//懒汉式:单例的延迟加载模式(先声明不创建对象)

      class Singleton1 {

//1,私有构造函数

privateSingleton1(){}

//2,声明一个本类的引用

private static Singleton1 s;

//3,对外提供公共的访问方法

public static Singleton1 getInstance() {

if(s == null)

//线程1等待,线程2等待(多线程访问会出现多次创建对象,有安全隐患)

s = new Singleton1();

return s;

}

public static void print() {

System.out.println("11111111111");

}

}

(3)第三种格式

class Singleton2 {

private Singleton2() {}

//final是最终的意思,被final修饰的变量不可以被更改

public static final Singleton2 s =

new Singleton2();

}

饿汉式和懒汉式的区别:

1,饿汉式:空间换时间,懒汉式:时间换空间

2,在多个线程访问时,饿汉式不会创建多个对象,而懒汉式有可能创建多个                       对象

多线程Runtime类

//获取运行时对象(单列设置)

Runtimer = Runtime.getRuntime();

//执行字符串命名(关机)

r.exec("shutdown -s -t 300");

//取消执行命令

r.exec("shutdown -a");

Timer计时器

Timer:一种工具,线程用其安排以后在后台线程中执行的任务,可安排任   务执行一次,或者定期重复执行

public class ThreadDemo12 {

public static void main(String[] args) throws InterruptedException {

Timert = new Timer();

//指定时间执行任务(年:当前年份-1900,月:0-11,日:1-31,时:24小时制,分:0-59,秒:0-59)

t.schedule(new MyTimerTask(), new Date(117, 2, 13, 18, 31,30));

//从指定时间开始,隔3s时间后重复执行

//第一个参数是执行的任务,第二个参数是执行的时间,第三个参数是过多长再时间重复

t.schedule(new MyTimerTask(), new Date(117, 2, 13, 18, 31,30),3000);

while(true){

Thread.sleep(1000);

System.out.println(new Date());

}

}

}

class MyTimerTask extends TimerTask{

@Override

public void run() {

System.out.println("起床");

}

}

两个线程间的通信

什么时候需要通信

多个线程并发执行时, 在默认情况下CPU是随机切换线程的

如果我们希望他们有规律的执行, 就可以使用通信, 例如每个线程执行一次                    打印

怎么通信

如果希望线程等待, 就调用wait()

如果希望唤醒等待的线程, 就调用notify();

这两个方法必须在同步代码中执行, 并且使用同步锁对象来调用

public class ThreadDemo01 {

public static void main(String[] args) {

final Printer p = new Printer();

new Thread(){

public void run() {

while(true){

try {

p.print1();

}catch (InterruptedException e) {

e.printStackTrace();

}

}

}

}.start();

new Thread(){

public void run() {

while(true){

try {

p.print2();

}catch (InterruptedException e) {

e.printStackTrace();

}

}

}

}.start();

}

}

//等待唤醒机制

class Printer {

private int flag = 1;

public void print1() throws InterruptedException {

synchronized (this) {

if(flag!=1){

//当前线程等待

this.wait();

}

System.out.print("好");

System.out.print("好");

System.out.print("学");

System.out.print("习");

System.out.print("\r\n");

flag = 2;

//随机唤醒单个等待的线程

this.notify();

}

}

public void print2() throws InterruptedException {

synchronized (this) {

if(flag!=2){

this.wait();

}

System.out.print("天");

System.out.print("天");

System.out.print("向");

System.out.print("上");

System.out.print("\r\n");

flag = 1;

this.notify();

}

}

}

三个或三个以上间的线程通信

多个线程通信的问题

notify()方法是随机唤醒一个线程

notifyAll()方法是唤醒所有线程

JDK5之前无法唤醒指定的一个线程

如果多个线程之间通信, 需要使用notifyAll()通知所有线程, 用while来                反复判断条件

下面是JDK1.5版本之前的处理方案

public class ThreadDemo2 {

public static void main(String[] args) {

Printer1p = new Printer1();

new Thread(){

public void run() {

while(true){

try {

p.print1();

}catch (InterruptedException e) {

e.printStackTrace();

}

}

}

}.start();

new Thread(){

public void run() {

while(true){

try {

p.print2();

}catch (InterruptedException e) {

e.printStackTrace();

}

}

}

}.start();

new Thread(){

public void run() {

while(true){

try {

p.print3();

}catch (InterruptedException e) {

e.printStackTrace();

}

}

}

}.start();

}

}

/**

* 1,在同步代码块中,用哪个对象锁,就用哪个对象调用wait方法

* 2,为什么wait方法和notify方法定义在Object类中?

*    因为锁对象可以是任意对象,Object是所有的类的基类

*    所以wait方法和notify方法需要定义在object这个类中

* 3,sleep方法和wait方法的区别?

* a,sleep方法必须传入参数,参数就是时间,时间到了自动唤醒

*    wait方法可以传入参数也可以不传入参数,传入参数就是在参数的时间结束后等待,不传入参数就是直接等待

* b,sleep在同步函数或同步代码块中不释放锁,wait方法在同步函数或者是同步代码块中释放锁

*

* @author LMD

*

*/

// 等待唤醒机制

class Printer1 {

private int flag = 1;

public void print1() throws InterruptedException {

synchronized (this) {

//if为啥换成while?因为wait方法在if(){wait}在哪里等待就在哪里起来,所以不会再进行像while那样的判断

while (flag != 1) {

// 当前线程等待

this.wait();

}

System.out.print("好");

System.out.print("好");

System.out.print("学");

System.out.print("习");

System.out.print("\r\n");

flag = 2;

// 随机唤醒单个等待的线程

//        this.notify();

this.notifyAll();

}

}

public void print2() throws InterruptedException {

synchronized (this) {

while (flag != 2) {

this.wait();

}

System.out.print("天");

System.out.print("天");

System.out.print("向");

System.out.print("上");

System.out.print("\r\n");

flag = 3;

//        this.notify();

this.notifyAll();

}

}

public void print3() throws InterruptedException {

synchronized (this) {

while (flag != 3) {//while是循环判断,每次都会判断标记

this.wait();

}

System.out.print("成");

System.out.print("为");

System.out.print("学");

System.out.print("霸");

System.out.print("\r\n");

flag = 1;

//        this.notify();

this.notifyAll();

}

}

}

JDK1.5的新特性互斥锁

同步:使用ReentrantLock类的lock()和unlock()方法进行同步

通信:

1,使用ReentrantLock类的newCondition()方法可以获取Condition对象

2,需要等待的时候使用Condition的await()方法, 唤醒时用signal()方法

3,不同的线程使用不同的Condition, 这样就能区分唤醒的时候找哪个线程了

public classReentrantLockDemo {

public static void main(String[] args) {

Printer2p = new Printer2();

new Thread() {

public void run() {

while (true) {

try {

p.print1();

}catch (InterruptedException e) {

e.printStackTrace();

}

}

}

}.start();

new Thread() {

public void run() {

while (true) {

try {

p.print2();

}catch (InterruptedException e) {

e.printStackTrace();

}

}

}

}.start();

new Thread() {

public void run() {

while (true) {

try {

p.print3();

}catch (InterruptedException e) {

e.printStackTrace();

}

}

}

}.start();

}

}

class Printer2 {

private ReentrantLock r = new ReentrantLock();

// 创建监视器

private Condition c1 = r.newCondition();

private Condition c2 = r.newCondition();

private Condition c3 = r.newCondition();

private int flag = 1;

public void print1() throws InterruptedException {

// 获取锁

r.lock();

// 每次只唤醒一个线程,所以不用进行循环判断

if (flag != 1) {

c1.await();

}

System.out.print("好");

System.out.print("好");

System.out.print("学");

System.out.print("习");

System.out.print("\r\n");

flag = 2;

c2.signal();

// 释放锁

r.unlock();

}

public void print2() throws InterruptedException {

// 获取锁

r.lock();

if (flag != 2) {

c2.await();

}

System.out.print("天");

System.out.print("天");

System.out.print("向");

System.out.print("上");

System.out.print("\r\n");

flag = 3;

c3.signal();

// 释放锁

r.unlock();

}

public void print3() throws InterruptedException {

// 获取锁

r.lock();

if (flag != 3) {

c3.await();

}

System.out.print("成");

System.out.print("为");

System.out.print("学");

System.out.print("霸");

System.out.print("\r\n");

flag = 1;

c1.signal();

// 释放锁

r.unlock();

}

}

线程组的概述和使用

线程组概述

a,Java中使用ThreadGroup来表示线程组,它可以对一批线程进行分类管理,                    Java允许程序直接对线程组进行控制。

b,默认情况下,所有的线程都属于主线程组。

c,public final ThreadGroup getThreadGroup()//通过线程对象获取                   他所属于的组

d,public final String getName()//通过线程组对象获取他组的名字

e,我们也可以给线程设置分组

1,ThreadGroup(Stringname) 创建线程组对象并给其赋值名字

2,创建线程对象

3,Thread(ThreadGroup?group,Runnable?target,                                              String?name)

4,设置整组的优先级或者守护线程

代码示例:

public class ThreadGroupDemo{

public static void main(String[] args) {

//     demo1();

//创建新的线程组

ThreadGrouptg = new ThreadGroup("我是一个新的线程组");

//创建Runnable的子类对象

MyRunnablemr = new MyRunnable();

//将线程t1放在线程组中

Threadt1 = new Thread(tg,mr,"张三");

//将线程t1放在线程组中

Threadt2 = new Thread(tg,mr,"李四");

//获取组名

System.out.println(t1.getThreadGroup().getName());

System.out.println(t2.getThreadGroup().getName());

//将整组变成守护线程

tg.setDaemon(true);

}

public static void demo1() {

MyRunnablemr = new MyRunnable();

Threadt1 = new Thread(mr,"张三");

Threadt2 = new Thread(mr,"李四");

//获取线程组

ThreadGrouptg1 = t1.getThreadGroup();

ThreadGrouptg2 = t2.getThreadGroup();

//默认是主线程

System.out.println(tg1.getName());

System.out.println(tg2.getName());

}

}

class MyRunnable implements Runnable{

@Override

public void run() {

for (int i = 0; i < 1000; i++) {   System.out.println(Thread.currentThread().

getName()+"....."+i);

}

}

}

线程的五种状态

线程池的概述和使用

线程池概述:程序启动一个新线程成本是比较高的,因为它涉及到要与操作系统  进行交互。而使用线程池可以很好的提高性能,尤其是当程序中要创建大量生存      期很短的线程时,更应该考虑使用线程池。线程池里的每一个线程代码结束后,    并不会死亡,而是再次回到线程池中成为空闲状态,等待下一个对象来使用。在   JDK5之前,我们必须手动实现自己的线程池,从JDK5开始,Java内置支持线程    池

内置线程池的使用概述

1,JDK5新增了一个Executors工厂类来产生线程池,有如下几个方法

2,public staticExecutorService newFixedThreadPool(int                         nThreads)创建一个可重用固定线程数的线程池

3,public staticExecutorService newSingleThreadExecutor()

4,这些方法的返回值是ExecutorService对象,该对象表示一个线程池,                       可以执行Runnable对象或者Callable对象代表的线程。它提供了如下                       方法

5,Future<?>submit(Runnable task)

6,<T>Future<T> submit(Callable<T> task)

使用步骤:

创建线程池对象

创建Runnable实例

提交Runnable实例

关闭线程池

程序示例:

public class ThreadDemo3 {

public static void main(String[] args) {

// 创建线程池

ExecutorServicepool = Executors.newFixedThreadPool(2);

// 将线程放进线程池并执行

pool.submit(new MyRunnable1());

pool.submit(new MyRunnable1());

// 关闭线程池

pool.shutdown();

}

}

class MyRunnable1 implements Runnable {

@Override

public void run() {

for (int i = 0; i < 1000; i++) {

System.out.println(Thread.currentThread().

getName()+ "....." + i);

}

}

}

多线程程序实现的方式3

提交的是Callable(其他两种是:继承Thread类,实现Runnable接口)

public class ThreadCallable {

public static void main(String[] args) throws InterruptedException, ExecutionException {

//创建线程池

ExecutorServicepool = Executors.newFixedThreadPool(2);

//将Callable的子类提交到线程池中,Future接收计算的结果

Future<Integer>f1 =pool.submit(new MyCallable(100));

Future<Integer>f2 = pool.submit(new MyCallable(50));

System.out.println(f1.get());

System.out.println(f2.get());

pool.shutdown();

}

}

class MyCallable implements Callable<Integer> {

private int num;

public MyCallable(int num) {

this.num = num;

}

@Override

public Integer call() throws Exception {

int sum = 0;

for (int i = 1; i <= num; i++) {

sum += i;

}

return sum;

}

}

多线程程序实现的方式3的好处和弊端

好处:可以有返回值,可以抛出异常

弊端:代码比较复杂,所以一般不用

简单工厂模式概述和使用

简单工厂模式概述:又叫静态工厂方法模式,它定义一个具体的工厂类负责创建                一些类的实例

优点:客户端不需要在负责对象的创建,从而明确了各个类的职责

缺点:这个静态工厂类负责所有对象的创建,如果有新的对象增加,或者某些对                象的创建方式不同,就需要不断的修改工厂类,不利于后期的维护

public class AnimalFactory {

//  public static Dog creatDog(){

//     return new Dog();

//  }

//  public static Cat creatCat(){

//     return new Cat();

//  }

//上面方法定义很多,复用性太差

public static AnimalcreateAnimal(String name){

if("Dog".equals(name)){

return new Dog();

}else if("Cat".equals(name)){

return new Cat();

}else{

return null;

}

}

}

工厂方法模式的概述和使用

工厂方法模式概述:工厂方法模式中抽象工厂类负责定义创建对象的接口,具体                       对象的创建工作由继承抽象工厂的具体类实现。

优点:客户端不需要在负责对象的创建,从而明确了各个类的职责,如果有新的                       对象增加,只需要增加一个具体的类和具体的工厂类即可,不影响已有的                          代码,后期维护容易,增强了系统的扩展性

缺点:需要额外的编写代码,增加了工作量

动物抽象类:public abstract class Animal{

public abstract void eat(); }

工厂接口:public interfaceFactory {

publicabstract Animal createAnimal();}

具体狗类:public class Dogextends Animal {}

具体猫类:public class Catextends Animal {}

(开始,在测试类中每个具体的内容自己创建对象,但是,创建对象的工作如果比 较麻烦,就需要有人专门做这个事情,所以就知道了一个专门的类来创建对象。      发现每次修改代码太麻烦,用工厂方法改进,针对每一个具体的实现提供一个具    体工厂)

狗工厂:public class DogFactory implements Factory {

public Animal createAnimal() {…}

}

猫工厂:public class CatFactory implements Factory {

public Animal createAnimal() {…}

}

具体使用

DogFactory df = new DogFactory();

df.eat();

如何创建一个窗口并显示

GraphicalUser Interface(图形用户接口)

//构造函数传入的是窗体title

Frame  f = new Frame("my window");

//设置布局管理器

f.setLayout(new FlowLayout());

//设置窗体大小

f.setSize(500,400);

//设置窗体出现在屏幕的位置

f.setLocation(300,200);

//设置图标

f.setIconImage(Toolkit.getDefaultToolkit().

createImage("img.jpg"));

//设置窗体可见

f.setVisible(true);

布局管理器

FlowLayout(流式布局管理器)

从左到右的顺序排列; Panel默认的布局管理器。

BorderLayout(边界布局管理器)

东,南,西,北,中;Frame默认的布局管理器

GridLayout(网格布局管理器):规则的矩阵

CardLayout(卡片布局管理器):选项卡

GridBagLayout(网格包布局管理器):非规则的矩阵

Frame f = new Frame("my window");

Buttonb1 = new Button("按钮1");

f.add(b1);

//设置布局管理器

f.setLayout(new FlowLayout());

f.setVisible(true);

窗体监听

Frame f = new Frame("我的窗体");

//事件源是窗体,把监听器注册到事件源上

//事件对象传递给监听器

f.addWindowListener(new WindowAdapter() {

@Override

public voidwindowClosing(WindowEvent e) {

//退出虚拟机,关闭窗口

System.exit(0);

}

});

鼠标监听

Buttonb1 = new Button("按钮1");

b1.addMouseListener(new MouseAdapter() {

//鼠标释放

@Override

public voidmouseReleased(MouseEvent e) {

//退出虚拟机,关闭窗口

System.exit(0);

}

});

键盘监听和键盘事件

b1.addKeyListener(new KeyAdapter() {

@Override

public voidkeyReleased(KeyEvent e) {

//获取键盘按下的键值code,空格退出

if(e.getKeyCode()==KeyEvent.VK_SPACE)

System.exit(0);

}

});

动作监听

//添加动作监听,应用场景:暂停视频和播放视频

b1.addActionListener(new ActionListener() {

@Override

public voidactionPerformed(ActionEvent e) {

System.exit(0);

}

});

事件处理

事件: 用户的一个操作

事件源: 被操作的组件

监听器: 一个自定义类的对象, 实现了监听器接口, 包含事件处理方法,把监                    听器添加在事件源上, 当事件发生的时候虚拟机就会自动调用监听器中              的事件处理方法

适配器设计模式

什么是适配器

1,在使用监听器的时候, 需要定义一个类事件监听器接口.

2,通常接口中有多个方法, 而程序中不一定所有的都用到, 但又必须重写,                            这很繁琐.

3,适配器简化了这些操作, 我们定义监听器时只要继承适配器, 然后重写需                         要的方法即可.

适配器原理

1,适配器就是一个类, 实现了监听器接口, 所有抽象方法都重写了, 但是方                          法全是空的.

2,适配器类需要定义成抽象的,因为创建该类对象,调用空方法是没有意义的

3,目的就是为了简化程序员的操作, 定义监听器时继承适配器, 只重写需要                         的方法就可以了

Java基础学习笔记4相关推荐

  1. 【Java基础学习笔记】- Day11 - 第四章 引用类型用法总结

    Java基础学习笔记 - Day11 - 第四章 引用类型用法总结 Java基础学习笔记 - Day11 - 第四章 引用类型用法总结 4.1 class作为成员变量 4.2 interface作为成 ...

  2. Java中大数据数组,Java基础学习笔记之数组详解

    摘要:这篇Java开发技术栏目下的"Java基础学习笔记之数组详解",介绍的技术点是"java基础学习笔记.基础学习笔记.Java基础.数组详解.学习笔记.Java&qu ...

  3. 尚学堂JAVA基础学习笔记_2/2

    尚学堂JAVA基础学习笔记_2/2 文章目录 尚学堂JAVA基础学习笔记_2/2 写在前面 第10章 IO技术 1. IO入门 2. IO的API 3. 装饰流 4. IO实战 5. CommonsI ...

  4. 【已完结!】Java基础--学习笔记(零起点打开java世界的大门)--博客汇总表【附:视频、工程源码、资料、详细笔记】

    java零基础入门到精通(2019版)[黑马程序员] 视频+资料(工程源码.笔记)[链接:https://pan.baidu.com/s/1MdFNUADVSFf-lVw3SJRvtg   提取码:z ...

  5. Java基础学习笔记(二)_Java核心技术(进阶)

    本篇文章的学习资源来自Java学习视频教程:Java核心技术(进阶)_华东师范大学_中国大学MOOC(慕课) 本篇文章的学习笔记即是对Java核心技术课程的总结,也是对自己学习的总结 文章目录 Jav ...

  6. Java基础学习笔记(三)_Java核心技术(高阶)

    本篇文章的学习资源来自Java学习视频教程:Java核心技术(高阶)_华东师范大学_中国大学MOOC(慕课) 本篇文章的学习笔记即是对Java核心技术课程的总结,也是对自己学习的总结 文章目录 Jav ...

  7. Java基础(学习笔记)

    其他文章链接 Java基础 Java集合 多线程 JVM MySQL Redis docker 计算机网络 操作系统 文章目录 前言 1.⾯向对象和⾯向过程的区别 2.Java 和 C++的共性与区别 ...

  8. Java基础学习笔记(完结)

    Java基础 前言 一.Java基础语法 1.注释 2.标识符 3.数据类型 4.类型转换 5.变量.作用域.常量 6. 运算符 二.Scanner与流程控制 1. Scanner对象 2. 流程控制 ...

  9. 【学习记录-java】Java基础学习笔记

    学习Java的一些笔记 前言 java中字符串的比较 Stream 流之 sorted 运算符 Java包(package)的命名规范&规则 SWITCH CASE java中import作用 ...

  10. Java基础 学习笔记7

    1.Java中的集合框架概述 Java中的集合类:是一种工具类,就像是容器,储存任意数量的具有共同属性的对象. 集合的作用: a.在类的内部,对数据进行组织 b.简单而快速的搜索大数量的条目 c.有的 ...

最新文章

  1. 个人作业1——四则运算题目生成程序
  2. 烧钱大战数以亿计 无人驾驶无法突破局限?
  3. native-maven-plugin与maven-nar-plugin配置
  4. web开发环境_Web开发人员的开发环境
  5. JSP(6)简单购物车实现
  6. UA OPTI512R 傅立叶光学导论14 卷积定理
  7. Ubuntu安装MDK5
  8. 单例模式中的懒汉模式和饿汉模式是什么?区别又是什么?
  9. python @property 解释
  10. 孔雀优化算法(POA)——(含MATLAB代码)
  11. 用钱宝显示无法连接服务器,用钱宝远程服务器繁忙
  12. Facebook Haystack 管理百亿照片
  13. [xueqi]吃着榨菜,轻松搞下漏洞百出的湾湾站
  14. Virut.ce-感染型病毒分析报告
  15. Linux之系统痕迹命令
  16. RC6加密解密算法C#实现源码!
  17. FCKeditor使用初步
  18. [葫芦侠三楼一键签到]网站源码 包含隐藏板块
  19. android 使用ios字体大小,iOS和Android 界面设计尺寸规范
  20. 科学计算机如何开机,CASIO科学计算机怎么进入EQN模式

热门文章

  1. wamp php不可用_使用wamp扩展php时出现服务未启动的解决方法
  2. 投影仪幕布增益_钱别瞎乱花 家用投影幕布应该怎么选?
  3. LQ0204 振兴中华【递归】
  4. 优思学院|六西格玛对于企业的作用,你了解多少?
  5. 安陆唐明惠 不堪回首的高考
  6. Lightly:新一代的 Cloud IDE
  7. pyhton GUI编程之Tkinter详细讲解二
  8. 使用Oracle VM VirtualBox完成Linux环境搭建openEuler
  9. 数字经济的观察与思考
  10. 工具篇——1、TMUX