给出最后 i、j、k 的值
public static void main(String[] args) { int i = 1; i = i++; int j = i++; int k = i + ++i * i++; System.out.println("i=" + i); System.out.println("j=" + j); System.out.println("k=" + k); }
结果: i = 4, j = 1, k = 11;
过程如下:
小结:
- 赋值 *** 作=最后计算,将 *** 作数栈赋值到局部变量表;
- =右侧元素从左到右加载值依次压入 *** 作数栈;
- *** 作数栈中的运算要依照运算符优先级;
- 自增、自减 *** 作直接在局部变量表中改变变量的值,不经过 *** 作数栈;
- 最后的赋值之前,临时结果也存储在 *** 作数栈中。
单例模式是Java中最简单的设计模式之一,这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
注:
- 单例类只能有一个实例:构造器私有化;
- 单例类必须自己创建自己的唯一实例:含有一个该类的静态变量来保存这个唯一的实例。
- 单例类必须给所有其他对象提供这一实例:对外提供获取该实例对象:(1)直接暴露;(2)用静态变量的get方法获取;
几种常见形式:
饿汉式 ,直接创建对象,不存在线程安全问题,具体分为:
- 直接实例化饿汉式(简洁直观)
- 枚举式(最简洁)
- 静态代码块饿汉式(适合复杂实例化)
懒汉式, 延迟创建对象,具体分为:
- 线程不安全(适用于单线程)
- 线程安全(适用于多线程)
- 静态内部类形式(适用于多线程)
保证在没有锁的状态下,多线程下保持一一致性实现值的改变。
ABA问题:分手,找别人,复合;中间的经历无法感知。
AtomicInteger
JUC是java.util.concurrent工具包的简称,这是一个处理线程的工具包,从JDK1.5开始出现。
进程与线程进程Process:是系统进行资源分配和调度的基本单位,是 *** 作系统结构的技术。进程是线程的容器,程序是指令、数据及组织形式的描述,进程是程序的实体。
线程Thread:是 *** 作系统能够进行运算掉的最小单位,它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
线程状态枚举类
public enum State { NEW,(新建) RUNNABLE,(准备就绪), BLOCKED,(阻塞) WAITING,(等待:不见不散,约个人五点到,五点不到会继续等) TIMED_WAITING,(等待:过时不候,约定时间未到直接走人) TERMINATED;(终结) }wait,sleep区别
- sleep()是Thread的静态方法;wait()是Object的方法,任何对象实例都能调用。
- sleep()执行时不会释放锁,也不需要占用锁;wait会释放锁,但是调用的前提是当前线程占有锁(即代码要在synchronized中)。
- 都可以被interrupted()方法中断,都是在哪里睡哪里醒。
管程即为Monitor监视器,保证了同一时刻只有一个进程在管程内活动,即管程内定义的 *** 作在同一时刻只能被一个线程访问被保护的数据或代码。
JVM同步基于进入加锁和退出解锁,使用管程对象实现的,每个Java对象都一个管程对象,随着java对象一同创建和销毁。
用户线程:平时用到的普通线程,如自定义线程。当主线程结束后,用户线程还在运行,JVM存活。
守护线程:运行在后台的特殊线程,比如垃圾回收。如果没有用户线程了,只剩下守护线程,jvm结束。守护线程的设置setDaemon(true)要在线程运行之前。
synchronized是Java中的关键字,是一种同步锁,它修饰的对象有以下几种:
- 修饰一个代码块,作用的对象是对用这个代码块的对象;
synchronized(this){ //修饰的是大括号中的代码 }
- 修饰一个方法,被修饰的方法称为同步方法,其作用范围是整个方法,作用对象是调用这个方法的对象。
- 修饰一个静态方法,作用范围是整个静态方法,作用的对象是这个类的所有对象。
- 修饰一个类;
多线程编程步骤:
- 创建资源类,在资源类创建属性和 *** 作方法(高内聚,低耦合:资源有什么就调用什么,没有就不调用)。
- 创建多个线程,调用资源类的 *** 作方法。
通过synchronized实现一个卖票实例,3个售票员卖出30张票,票类Ticket有属性number记录票数目,方法sale()进行卖票并且通过synchronized加锁,
package com.jiayuleng.jucstudy.sync; class Ticket { // 票数 private int number = 30; // *** 作方法:买票 public synchronized void sale() { // 判断:是否有票; if(number > 0) { System.out.println(Thread.currentThread().getName() + ": 卖出:" + (number--) + " 剩下:" + number); } } } public class SaleTicket { // 第二步 创建多个线程,调用资源类的 *** 作方法 public static void main(String[] args) { Ticket ticket = new Ticket(); new Thread(new Runnable() { @Override public void run() { for(int i = 0; i < 40; i++) { ticket.sale(); } } }, "AA").start(); new Thread(new Runnable() { @Override public void run() { for(int i = 0; i < 40; i++) { ticket.sale(); } } }, "bb").start(); new Thread(new Runnable() { @Override public void run() { for(int i = 0; i < 40; i++) { ticket.sale(); } } }, "cc").start(); } }
如果不加锁,会出现线程不同步的情况。
- 创建一个继承于Thread类的子类。
- 重写Thread类的run()方法,将此线程执行的 *** 作声明在run()中。
- 创建Thread类的子类的对象。
- 通过此类调用start()方法。
例,通过子线程输出[0, 100)的偶数
package com.jiayuleng.javabasestudy.threadstudy.threadcreate; // 1.创建一个继承于Thread类的子类。 // 2.重写Thread类的run()方法,将此线程执行的 *** 作声明在run()中。 // 3.创建Thread类的子类的对象。 // 4.通过此类调用start()方法。 //例子:遍历100以内的所有的偶数 class MyThread extends Thread { @Override public void run() { for(int i = 0; i < 100; i++) { if(i % 2 == 0) { System.out.println(i); } } } } public class ThreadTest { public static void main(String[] args) { MyThread t1 = new MyThread(); t1.start(); for(int i = 0; i < 100; i++) { if(i % 2 == 0) { System.out.println(i + "******main*******"); } } } }
主线程与子线程交替运行如下图
问题一:我们不能通过直接调用run()的方式启动线程,start()方法会先启动当前线程,再调用当前线程的run()方法。
问题二:同一个线程对象不可以启动start()方法两次,会报IllegalThreadStateException异常;
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)